最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

zone.js由入門到放棄之二——zone.js API大練兵

2023-08-30 11:07 作者:OpenTiny社區(qū)  | 我要投稿

這是來自@孫嘯達(dá) 同學(xué)的zone.js系列文章第二篇,這篇文章主要為我們介紹了Zone和ZoneTask

zone.js系列往期文章

  • zone.js由入門到放棄之一——通過一場(chǎng)游戲認(rèn)識(shí)zone.js

zone.js中最重要的三個(gè)定義為:Zone,ZoneDelegate,ZoneTask。搞清楚了這三個(gè)類的API及它們之間關(guān)系,基本上對(duì)zone.js就通了。而Zone,ZoneDelegate,ZoneTask三者中,Zone,ZoneDelegate其實(shí)半差不差的可以先當(dāng)成一個(gè)東西。所以文中,我們集中火力主攻Zone和ZoneTask。

Zone

傳送門



Zone中的API大致分了三類:通用API、Wrap類和Task類。Wrap和Task類分別對(duì)應(yīng)zone.js對(duì)異步方法的兩種打包方式(Patch),不同的打包方式對(duì)異步回調(diào)提供了不同粒度的"監(jiān)聽"方式,即不同的打包方式會(huì)暴露出不同的攔截勾子。你可以根據(jù)自身對(duì)異步的控制精度選擇不同的打包方式。

Wrap方式:

  • onInvoke

  • onIntercept

Task方式

  • onScheduleTask

  • onInvokeTask

  • onCancelTask

  • onHasTask

上文說到了,zone.js在初始化的時(shí)候已經(jīng)把大多數(shù)常見的異步API都打包過了(就是用的上面這些API打包的),除了這些默認(rèn)被打包的API以外,zone.js也支持用戶對(duì)一些自研的API或是一些依賴中API自行打包。下圖展示了一些已經(jīng)被zone.js默認(rèn)打包的API,感興趣的可以了解一下:

通用API

zone.js的current和get在上一篇文章中已經(jīng)介紹過了,因?yàn)楸旧硪膊惶y,這里就不專門舉例了。

  • ??current:獲取當(dāng)前的zone上下文

  • ??get:從properties中獲取當(dāng)前zone中的屬性。properties屬性其實(shí)是immutable的,上一篇文章中直接對(duì)properties進(jìn)行修改其實(shí)是不推薦的。同時(shí),由于zone之間是可以通過fork嵌套的,所以子zone可以繼承父zone的properties。

  • ??fork(zoneSpec: ZoneSpec):fork方法可以給當(dāng)前Zone創(chuàng)建一個(gè)子Zone,函數(shù)接受一個(gè)ZoneSpec的參數(shù),參數(shù)規(guī)定了當(dāng)前Zone的一些基本信息以及需要注入的勾子。下面展示了ZoneSpec的所有屬性:

傳送門



  • ?run(callback: Function, applyThis?: any, applyArgs?: any[], source?: string): T;

  • ?runGuarded(callback: Function, applyThis?: any, applyArgs?: any[], source?: string): T;

  • ?runTask(task: Task, applyThis?: any, applyArgs?: any;

runXXX方法可以指定函數(shù)運(yùn)行在特定的zone上,這里可以把該方法類比成JS中的call或者apply,它可以指定函數(shù)所運(yùn)行的上下文環(huán)境;而zone在這里可以類比成特殊的this,只不過zone上下文可以跨執(zhí)行棧保存,而this不行。與此同時(shí),runXXX在回調(diào)執(zhí)行結(jié)束后,會(huì)自動(dòng)地恢復(fù)zone的執(zhí)行環(huán)境。

Demo1:zone的一些基操

看過一篇的對(duì)這個(gè)例子應(yīng)該不陌生了,這個(gè)例子主要演示了如何通過zone.js的通用API創(chuàng)建zone,并在特定的zone上下文中執(zhí)行函數(shù)。


Demo2:runXXX

  • ?wrap(callback: F, source: string): F;

前文說了runXXX方法類似于call和apply的作用,那么wrap方法類似于JS中的bind方法。wrap可以將執(zhí)行函數(shù)綁定到當(dāng)前的zone中,使得函數(shù)也能執(zhí)行在特定的zone中。下面是我簡(jiǎn)化以后的wrap源碼:


wrap本身卻是什么也沒做,只是維護(hù)了對(duì)runGuarded方法的調(diào)用。runGuarded方法其實(shí)也沒有什么神奇之處,它內(nèi)部就是對(duì)run方法的一個(gè)調(diào)用,只不過runGuarded方法會(huì)嘗試捕獲一下run方法執(zhí)行過程中拋出的異常。下面是run和runGuarded的源碼比較,看下runGuarded對(duì)比run是不是就多了一個(gè)catch?

傳送門


Demo3:onHandleError

上面介紹,run和runGuarded就只差一個(gè)catch,那么這個(gè)catch中調(diào)用的handleError方法又是做什么的?其實(shí)handleError實(shí)際觸發(fā)的是zone中的一個(gè)鉤子函數(shù)onHandleError。我們可以在定義一個(gè)zone的時(shí)候?qū)⑵涠x在zoneSpec中,此時(shí),當(dāng)函數(shù)運(yùn)行過程中出現(xiàn)了未捕獲異常的時(shí)候,該鉤子函數(shù)會(huì)被觸發(fā)。注意,這里是未捕獲的異常,如果異常已經(jīng)被捕獲,則該鉤子不會(huì)觸發(fā)。感興趣的可以在reject后面直接catch異常,看下此時(shí)onHandleError還會(huì)不會(huì)執(zhí)行。


Demo4: onIntercept & onInvoke

  • ?onIntercept:當(dāng)在注冊(cè)回調(diào)函數(shù)時(shí)被觸發(fā),簡(jiǎn)單點(diǎn)理解在調(diào)用wrap的時(shí)候,該勾子被調(diào)用

  • ?onInvoke: 當(dāng)通過wrap包裝的函數(shù)調(diào)用時(shí)被觸發(fā)

onIntercept一般用的很少,我也沒有想到特別好的使用場(chǎng)景。下面這個(gè)例子通過onIntercept勾子“重定義”了回調(diào)函數(shù),在回調(diào)函數(shù)之前又加了一段打印。所以個(gè)人認(rèn)為,onIntercept可以用來對(duì)包裝函數(shù)做一些通用的AOP增強(qiáng)。

onInvoke會(huì)在下一篇源碼分析中大量出現(xiàn),每當(dāng)包裝函數(shù)要執(zhí)行時(shí)就會(huì)觸發(fā)Zone(實(shí)際是ZoneDelegate)的invoke方法時(shí),介時(shí)onInvoke勾子方法就會(huì)被調(diào)用。

下面的例子中,先通過wrap函數(shù)將setTimeout的回調(diào)包裝,并將回調(diào)的執(zhí)行綁定到apiZone上。當(dāng)回調(diào)函數(shù)執(zhí)行時(shí),onInvoke被調(diào)用。這里通過onInvoke勾子打印了一下回調(diào)執(zhí)行時(shí)間,從而側(cè)面說明了onInvoke的執(zhí)行時(shí)機(jī)。


講到這里Zone的通用API和Wrap打包方式就講完了,相信大家都有點(diǎn)累,休息一下吧

ZoneTask

zone.js打包了大多數(shù)你見到過的異步方法,其中有很大一部分被打包成Task的形式。Task形式比Wrap形式有更豐富的生命周期勾子,使得你可以更精細(xì)化地控制每個(gè)異步任務(wù)。好比Angular,它可以通過這些勾子決定在何時(shí)進(jìn)行臟值檢測(cè),何時(shí)渲染UI界面。

zone.js任務(wù)分成MacroTask、MicroTask和EventTask三種:

  • MicroTask:在當(dāng)前task結(jié)束之后和下一個(gè)task開始之前執(zhí)行的,不可取消,如Promise,MutationObserver、process.nextTick

  • MacroTask:一段時(shí)間后才執(zhí)行的task,可以取消,如setTimeout, setInterval, setImmediate, I/O, UI rendering

  • EventTask:監(jiān)聽未來的事件,可能執(zhí)行0次或多次,執(zhí)行時(shí)間是不確定的

Demo5:SetTimeout Task

zone.js對(duì)Task的生命周期勾子:

  • ?onScheduleTask:當(dāng)一步操作被探測(cè)出的時(shí)候調(diào)用

  • ?onInvokeTask:當(dāng)回調(diào)執(zhí)行時(shí)被調(diào)用

  • ?onHasTask:當(dāng)隊(duì)列狀態(tài)發(fā)生改變時(shí)被調(diào)用

單看對(duì)著三個(gè)勾子函數(shù)的介紹,很難清楚地認(rèn)識(shí)到他們的意思和觸發(fā)時(shí)機(jī)。我以setTimeout為例,介紹一下我對(duì)這幾個(gè)勾子的理解,這里會(huì)涉及到一些源碼邏輯,這些會(huì)在第三篇文章中詳細(xì)說明,這里了解個(gè)大概即可。

首先,zone初始化的時(shí)候會(huì)monkey patch原生的setTimeout方法。之后,每當(dāng)setTimeout被調(diào)用時(shí),patch后的方法都會(huì)把當(dāng)前的異步操作打包成Task,在調(diào)用真正的setTimeout之前會(huì)觸發(fā)onScheduleTask。

將setTimeout打包成Task后,這個(gè)異步任務(wù)就會(huì)進(jìn)入到zone的管控之中。接下來,Task會(huì)將setTimeout回調(diào)通過wrap打包,所以當(dāng)回調(diào)執(zhí)行時(shí),zone也是可以感知的。當(dāng)回調(diào)被執(zhí)行之前,onInvokeTask勾子會(huì)被觸發(fā)。onInvokeTask執(zhí)行結(jié)束后,才會(huì)執(zhí)行真正的setTimeout回調(diào)。

onHasTask這個(gè)勾子比較有意思,它記錄了任務(wù)隊(duì)列的狀態(tài)。當(dāng)任務(wù)隊(duì)列中有MacroTask、MicroTask或EventTask進(jìn)隊(duì)或出隊(duì)時(shí)都會(huì)觸發(fā)該勾子函數(shù)。

下圖是一個(gè)onHasTask中維護(hù)隊(duì)列狀態(tài)的示例,該狀態(tài)表明了有一個(gè)MacroTask任務(wù)進(jìn)入了隊(duì)列。


這是一個(gè)MacroTask出隊(duì)的示例:


下面這個(gè)示例onHasTask被調(diào)用兩次,第一次是setTimeout時(shí)間進(jìn)入任務(wù)隊(duì)列;第二次是setTimeout執(zhí)行完畢,移出任務(wù)隊(duì)列。同時(shí)在onScheduleTask和onInvokeTask中,也可以通過task.type獲取到當(dāng)前的任務(wù)類型。


Demo6:多任務(wù)跟蹤

為了能認(rèn)清zone.js對(duì)跟異步任務(wù)的跟蹤能力,我們模擬多個(gè)、多種異步任務(wù),測(cè)試一下zone.js對(duì)這些任務(wù)的跟蹤能力。下面例子,zone.js分別監(jiān)控了5個(gè)setTimeout任務(wù)和5個(gè)Promise任務(wù)。從結(jié)果上看,zone內(nèi)部可以清楚地知道各種類型的任務(wù)什么時(shí)候創(chuàng)建、什么時(shí)候執(zhí)行、什么時(shí)候銷毀。Angular正是基于這一點(diǎn)進(jìn)行變更檢測(cè)的,ngZone中的stable狀態(tài)也是由此產(chǎn)生的,這個(gè)我們會(huì)在系列的第四篇中介紹。


Demo7:手動(dòng)打包setTimeout

我們最后還有3個(gè)API沒有講:scheduleMacroTask、scheduleMicroTask、scheduleEventTask。zone.js通過這三個(gè)方法將普通的異步方法打包成異步任務(wù)。這三個(gè)方法屬于比較底層的API,一般很少會(huì)用,因?yàn)榇蟛糠諥PI的打包zone已經(jīng)幫我們實(shí)現(xiàn)了。為了介紹一下這個(gè)API的使用,今天就頭鐵??????一次,使用scheduleMacroTask打包一個(gè)我們自己的setTimeout。

準(zhǔn)備

我們知道,zone.js默認(rèn)會(huì)打包setTimeout的,打包后的setTimeout變成Task被管控起來。所以,我們可以通過Task的勾子有沒有觸發(fā)判斷setTimeout有沒有被打包。下面代碼為例,當(dāng)onHasTask事件觸發(fā),我們才能斷定setTimeout已經(jīng)被打包成Task。


Step1:取消zone.js原生打包

zone.js初始化時(shí)會(huì)自動(dòng)打包setTimeout函數(shù),所以我們第一步要做的就是禁止zone.js自動(dòng)打包setTimeout。自zone.js v0.8.9以后,zone.js支持用戶通過配置自主選擇需要打包的函數(shù)。比如本例中,只需要對(duì)__Zone_disable_timers進(jìn)行設(shè)置就可以關(guān)閉zone.js對(duì)setTimeout的打包。

global.__Zone_disable_timers = true;

Step2:偷梁換柱

改造setTimeout的第一步就是要保存原始的setTimeout:

const originalSetTineout = global.setTimeout;

Step3:scheduleMacroTask

scheduleMacroTask用來將異步方法打包成Task。值得注意的是scheduleMacroTask的最后一個(gè)參數(shù),要求傳入一個(gè)Task的調(diào)度方法。這個(gè)方法返回了原生的setTimeout方法,只是把回調(diào)函數(shù)換成了task.invoke。看到這,你對(duì)zone.js的認(rèn)識(shí)應(yīng)該越來越清晰了,task.invoke中就是zone對(duì)回調(diào)函數(shù)的打包。打包的結(jié)果就是讓回調(diào)可以在正確地zone上下文中被執(zhí)行。


最后,完整代碼奉上:


總結(jié)

本文重點(diǎn)介紹了zone.js中各個(gè)API的使用方式及相互間關(guān)系,通過大量的實(shí)驗(yàn)demo簡(jiǎn)單演示了一下這些API的用法。最后,還通過一個(gè)較底層的API打包了自己的Task。當(dāng)然,本文最后這個(gè)對(duì)setTimeout的打包還是太過粗糙,原生的打包要比這個(gè)復(fù)雜的多。即便如此,我相信看到這里的童鞋們應(yīng)該已經(jīng)對(duì)zone.js背后的邏輯有了一定的認(rèn)識(shí)了。

下一篇文章,我準(zhǔn)備對(duì)zone.js的打包原理做更深的分析。大家可以跟我一起深入到源碼看看zone.js在打包setTimeout時(shí)做了哪些工作。

關(guān)于 OpenTiny

OpenTiny 是一套企業(yè)級(jí)組件庫解決方案,適配 PC 端 / 移動(dòng)端等多端,涵蓋 Vue2 / Vue3 / Angular 多技術(shù)棧,擁有主題配置系統(tǒng) / 中后臺(tái)模板 / CLI 命令行等效率提升工具,可幫助開發(fā)者高效開發(fā) Web 應(yīng)用。

核心亮點(diǎn):

  1. 跨端跨框架:使用 Renderless 無渲染組件設(shè)計(jì)架構(gòu),實(shí)現(xiàn)了一套代碼同時(shí)支持 Vue2 / Vue3,PC / Mobile 端,并支持函數(shù)級(jí)別的邏輯定制和全模板替換,靈活性好、二次開發(fā)能力強(qiáng)。

  2. 組件豐富:PC 端有100+組件,移動(dòng)端有30+組件,包含高頻組件 Table、Tree、Select 等,內(nèi)置虛擬滾動(dòng),保證大數(shù)據(jù)場(chǎng)景下的流暢體驗(yàn),除了業(yè)界常見組件之外,我們還提供了一些獨(dú)有的特色組件,如:Split 面板分割器、IpAddress IP地址輸入框、Calendar 日歷、Crop 圖片裁切等

  3. 配置式組件:組件支持模板式和配置式兩種使用方式,適合低代碼平臺(tái),目前團(tuán)隊(duì)已經(jīng)將 OpenTiny 集成到內(nèi)部的低代碼平臺(tái),針對(duì)低碼平臺(tái)做了大量?jī)?yōu)化

  4. 周邊生態(tài)齊全:提供了基于 Angular + TypeScript 的 TinyNG 組件庫,提供包含 10+ 實(shí)用功能、20+ 典型頁面的 TinyPro 中后臺(tái)模板,提供覆蓋前端開發(fā)全流程的 TinyCLI 工程化工具,提供強(qiáng)大的在線主題配置平臺(tái) TinyTheme

聯(lián)系我們:

  • 官方公眾號(hào):OpenTiny

  • OpenTiny 官網(wǎng):https://opentiny.design/

  • OpenTiny 代碼倉(cāng)庫:https://github.com/opentiny/

  • Vue 組件庫:https://github.com/opentiny/tiny-vue?(歡迎 Star)

  • Angluar組件庫:https://github.com/opentiny/ng?(歡迎 Star)

  • CLI工具:https://github.com/opentiny/tiny-cli?(歡迎 Star)

更多視頻內(nèi)容也可以關(guān)注OpenTiny社區(qū),B站/抖音/小紅書/視頻號(hào)。


zone.js由入門到放棄之二——zone.js API大練兵的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國(guó)家法律
丰宁| 本溪| 德兴市| 卫辉市| 开江县| 宜黄县| 阳曲县| 永修县| 德阳市| 烟台市| 东丰县| 白朗县| 偏关县| 阜新市| 库车县| 潮安县| 绵阳市| 开平市| 乐亭县| 庆阳市| 青铜峡市| 于田县| 尚义县| 张家界市| 临邑县| 宜兴市| 丰镇市| 唐海县| 天台县| 南和县| 邹平县| 右玉县| 封开县| 周宁县| 陕西省| 佛冈县| 龙州县| 罗源县| 泾阳县| 长岛县| 南投市|