Delegate是个好东西,看看孙啸达 同学对ZoneDelegate的介绍吧,这是他关于zone.js系列文章的第三篇~
zone.js系列往期文章
- zone.js由入门到放弃之一——通过一场游戏认识zone.js
- zone.js由入门到放弃之二——zone.js API大练兵
zone.js源码分析
接下来的全是干货,从头到尾,一干到底
一点前置:Zone 和 ZoneDelegate
在前文中,我们一直在回避讲解Zone和ZoneDelegate之间的区别。尤其在上篇文章讲API的时候,我甚至让大家把这两者当成一回事。其实这两者并不是完全相等的。单从Delegate这个单词你也能看出,虽然Zone和ZoneDelegate的API很像,但是真正干活的是ZoneDelegate。我简单节选几段Zone的源码,大家不难发现,大多数Zone的API都直接或间接通过代理中相对应的API完成的。
public fork(zoneSpec: ZoneSpec): AmbientZone {
// 此处省略成吨源码
return this._zoneDelegate.fork(this, zoneSpec);
}
public run<T>(callback: (...args: any[]) => T, applyThis?: any, applyArgs?: any[], source?: string): T {
// 此处省略成吨源码
return this._zoneDelegate.invoke(this, callback, applyThis, applyArgs, source);
}
runTask(task: Task, applyThis?: any, applyArgs?: any): any {
// 此处省略成吨源码
return this._zoneDelegate.invokeTask(this, task, applyThis, applyArgs);
}
我把上篇文章讲到的API和ZoneDelegate之间的调用关系简单梳理了一下。下文在分析源码的时候,会有大量Zone、ZomeDelegate、ZomeTask三者之间相互调用的场景,实在理不清的地方可以返回这里看下。
虽然ZoneDelegate实际承担了大量的工作,但是Zone也不是甩手掌柜,啥活儿也不干。在我个人看来,Zone其实主要只负责两件事:
- 维护Zone的上下文栈:我们知道Zone是个具有继承关系的链式结构。zone.js在全局会维护一个Zone栈帧,每当我们在某个Zone中执行代码时,Zone要负责将当前的Zone上下文置于栈帧中;当代码执行完毕,又要负责将Zone栈帧恢复回去。
public run<T>(callback: (...args: any[]) => T, applyThis?: any, applyArgs?: any[], source?: string): T {
// 将当前的Zone上下文置于栈帧中
_currentZoneFrame = {parent: _currentZoneFrame, zone: this};
try {
...
} finally {
// 恢复Zone栈帧
_currentZoneFrame = _currentZoneFrame.parent!;
}
}
- Zone还负责ZoneTask的状态切换。上文说过,Zone可以对宏任务、微任务、事件进行管理。那么每个任务在Zone中处于何种阶段、何种状态也是由Zone负责的。Zone会在适当时候调用ZoneTask的_transitionTo方法切换ZoneTask的状态。
接下来会把zone.js对setTimeout的Patch过程进行详细的说明,为了方便理解,其中涉及的大量源码都是我简化之后。
第一阶段:zone.js打包setTimeout
Patch第一站
zone.js提供一个静态方法用于Patch我们常见的API,对setTimeout的Patch位于zone.js/lib/browser/browser.ts
下:其中这个patchTimer(global, set, clear, 'Timeout');
就是本次源码分析的起点。
Zone.__load_patch('timers', (global: any) => {
const set = 'set';
const clear = 'clear';
patchTimer(global, set, clear, 'Timeout');
标签:task,zone,Zone,js,Task,源码,setTimeout
From: https://blog.51cto.com/u_16152776/7389084