Angular ngZone 源码解析

Angular ngZone 源码解析

ngZone 源码中有几个常用的方法,属性,这里做一个整理与总结

Zone.js简介

ZoneJs 职责

  • 拦截异步任务的调度
  • 封装回调函数用于异常处理以及异步操作中zone的跟踪
  • 提供往zone中添加数据的方法
  • 提供上下文特定的最后一帧错误处理
  • 拦截阻塞方法

Zone 的底层异步Task模型

  • MicroTask 微任务,这个是在当前task 之后立刻执行的,不可取消.肯定是在当前的VM turn。
  • MacroTask 宏任务,这个肯定是不在当前的VM turn内的。一个很好定义合理的延迟执行的任务e.g.setTimeout,setInternal,requestAnimationFrame
  • EventTask 事件任务。

Zone 的属性方法。下面是配置项的解构,可以感知到zone 内部会是啥样的

/**
 * Provides a way to configure the interception of zone events.
 *
 * Only the `name` property is required (all other are optional).
 */
interface ZoneSpec {
  /**
   * The name of the zone. Useful when debugging Zones.
   */
  name: string;

  /**
   * A set of properties to be associated with Zone. Use [Zone.get] to retrieve them.
   */
  properties?: {[key: string]: any};

  /**
   * Allows the interception of zone forking.
   *
   * When the zone is being forked, the request is forwarded to this method for interception.
   *
   * @param parentZoneDelegate Delegate which performs the parent [ZoneSpec] operation.
   * @param currentZone The current [Zone] where the current interceptor has been declared.
   * @param targetZone The [Zone] which originally received the request.
   * @param zoneSpec The argument passed into the `fork` method.
   */
  onFork?:
      (parentZoneDelegate: ZoneDelegate, currentZone: Zone, targetZone: Zone,
       zoneSpec: ZoneSpec) => Zone;

  /**
   * Allows interception of the wrapping of the callback.
   *
   * @param parentZoneDelegate Delegate which performs the parent [ZoneSpec] operation.
   * @param currentZone The current [Zone] where the current interceptor has been declared.
   * @param targetZone The [Zone] which originally received the request.
   * @param delegate The argument passed into the `wrap` method.
   * @param source The argument passed into the `wrap` method.
   */
  onIntercept?:
      (parentZoneDelegate: ZoneDelegate, currentZone: Zone, targetZone: Zone, delegate: Function,
       source: string) => Function;

  /**
   * Allows interception of the callback invocation.
   *
   * @param parentZoneDelegate Delegate which performs the parent [ZoneSpec] operation.
   * @param currentZone The current [Zone] where the current interceptor has been declared.
   * @param targetZone The [Zone] which originally received the request.
   * @param delegate The argument passed into the `run` method.
   * @param applyThis The argument passed into the `run` method.
   * @param applyArgs The argument passed into the `run` method.
   * @param source The argument passed into the `run` method.
   */
  onInvoke?:
      (parentZoneDelegate: ZoneDelegate, currentZone: Zone, targetZone: Zone, delegate: Function,
       applyThis: any, applyArgs?: any[], source?: string) => any;

  /**
   * Allows interception of the error handling.
   *
   * @param parentZoneDelegate Delegate which performs the parent [ZoneSpec] operation.
   * @param currentZone The current [Zone] where the current interceptor has been declared.
   * @param targetZone The [Zone] which originally received the request.
   * @param error The argument passed into the `handleError` method.
   */
  onHandleError?:
      (parentZoneDelegate: ZoneDelegate, currentZone: Zone, targetZone: Zone,
       error: any) => boolean;

  /**
   * Allows interception of task scheduling.
   *
   * @param parentZoneDelegate Delegate which performs the parent [ZoneSpec] operation.
   * @param currentZone The current [Zone] where the current interceptor has been declared.
   * @param targetZone The [Zone] which originally received the request.
   * @param task The argument passed into the `scheduleTask` method.
   */
  onScheduleTask?:
      (parentZoneDelegate: ZoneDelegate, currentZone: Zone, targetZone: Zone, task: Task) => Task;

  onInvokeTask?:
      (parentZoneDelegate: ZoneDelegate, currentZone: Zone, targetZone: Zone, task: Task,
       applyThis: any, applyArgs?: any[]) => any;

  /**
   * Allows interception of task cancellation.
   *
   * @param parentZoneDelegate Delegate which performs the parent [ZoneSpec] operation.
   * @param currentZone The current [Zone] where the current interceptor has been declared.
   * @param targetZone The [Zone] which originally received the request.
   * @param task The argument passed into the `cancelTask` method.
   */
  onCancelTask?:
      (parentZoneDelegate: ZoneDelegate, currentZone: Zone, targetZone: Zone, task: Task) => any;

  /**
   * Notifies of changes to the task queue empty status.
   *
   * @param parentZoneDelegate Delegate which performs the parent [ZoneSpec] operation.
   * @param currentZone The current [Zone] where the current interceptor has been declared.
   * @param targetZone The [Zone] which originally received the request.
   * @param hasTaskState
   */
  onHasTask?:
      (parentZoneDelegate: ZoneDelegate, currentZone: Zone, targetZone: Zone,
       hasTaskState: HasTaskState) => void;
}
  • get(key:string):any 这个是从properties里面取值
  • wrap<F extends Function>(callback: F, source: string): F;在当前zone 中封装一个函数,当这个函数被执行时,会在当前的zone 中执行。跟apply/bind神似。
  • run<T>(callback: Function, applyThis?: any, applyArgs?: any[], source?: string): T;在当前的zone中执行函数
  • runGuarded<T>(callback: Function, applyThis?: any, applyArgs?: any[], source?: string): T;与上面的方法类似,区别在于异常处理会在当前的zone 中接管,如果没有处理会rethrow.
  • runTask<T>(task: Task, applyThis?: any, applyArgs?: any): T;执行当前zone 中执行一个Task(上面指定的三个task,micro/macro/eventtask)。这个方法属于底层方法.
  • scheduleMicroTask(source: string, callback: Function, data?: TaskData,customSchedule?: (task: Task) => void): MicroTask;
  • scheduleMacroTask(source: string, callback: Function, data?: TaskData, customSchedule?: (task: Task) => void,customCancel?: (task: Task) => void): MacroTask;
  • scheduleEventTask(source: string, callback: Function, data?: TaskData, customSchedule?: (task: Task) => void, customCancel?: (task: Task) => void): EventTask;
  • scheduleTask<T extends Task>(task: T): T;这个方法也是内部方法,上面三种schedule其实是调用的它。定义/安排一个task
  • cancelTask(task: Task): any;
  • fork(zoneSpec: ZoneSpec): Zone;创建一个子Zone,

class 继承关系

  • interface NgZonePrivate extends NgZone
  • class NoopNgZone implements NgZone
    这个是一个空类,啥也不干

直接介绍ngZone

方法

  • runOutsideAngular<T>(fn: (...args: any[]) => T): T,这个经常用,将某个方法的执行置于ngZone 之外。
  • run<T>(fn: (...args: any[]) => T, applyThis?: any, applyArgs?: any[]): T,将某个方法置于ngZone中执行。
  • runTask<T>(fn: (...args: any[]) => T, applyThis?: any, applyArgs?: any[], name?: string): T eventtask的方式来执行某个方法。这个方法好像是给angular 用的,会发布一些事件NgZoneEvent: xxx
  • static isInAngularZone(): boolean 判断当前是否在angular zone 里面

属性

  • isStable: boolean用于标记当前的zone 中没有未执行的Micro/Macro Task

事件

  • onUnstable: EventEmitter<any> = new EventEmitter(false)当代码进入angularZone的时候。或者说有代码被ngZone拦截的时候。这个时候一般是发生在VM turn刚开始的时候,也就是一个宏任务开始的时候,例如setTimeout里面的callback函数开始执行的时候。
  • onMicrotaskEmpty: EventEmitter<any>这个标记当前VM Turn里面所有的微任务都执行结束了。这个会指示Angular,你可以做ChangeDetect了。当然Angular的框架在CD的过程中也会参数更多的微任务。所以这个事件会很频繁的被发布。
  • onStable: EventEmitter<any> = new EventEmitter(false)。当最后一个onMicrotaskEmpty被发布后。再也没有微任务了。这个时候会发布这个事件,这个事件一般是在终止VM Turn 的时候发布。意味着Angular 完成了CD,没有未执行的js 代码了。页面完全处于idle 状态。
  • onError: EventEmitter<any>

注意点

  • 宏任务/微任务 跟js事件模型里面的是一致的。ngZone,通过对宏任务/微任务进行拦截。这些任务在ngZone里面统一被称为Task。只是类型不同。这些Task 的执行是在ngZone 里面的,所以ngZone 能够感知到这些事件。其实当宏任务被执行的时候,它在ngZone里面以及被当成了js 的微任务。
  • Angular 框架在onMicrotaskEmpty发出的时候,可能会触发CD.所以这个方法可能会触发多次。
posted @ 2023-05-16 16:58  kongshu  阅读(75)  评论(0编辑  收藏  举报