首页 > 编程语言 >zone.js由入门到放弃之五——NgZone & ApplicationRef源码分析

zone.js由入门到放弃之五——NgZone & ApplicationRef源码分析

时间:2023-09-19 21:04:49浏览次数:68  
标签:ApplicationRef zone js NgZone 任务 源码 组件 执行

啸达同学刚写zone.js系列就说过,NgZone影响着Angular中的变更检测,历时一个多月的笔耕不辍,终于到了他初次下笔时的目的地~

zone.js系列

初见NgZone

其实在上一篇文章中,大家已经初步窥探过NgZone的芳容了。而且我们也知道了,在NgZone中维护了OuterZone和InnerZone两个Zone。今天的这篇文章,我们主要分析一下InnerZone,并看一下InnerZone是如何跟Angular的变更检测联系到一起的。

zone.js由入门到放弃之五——NgZone & ApplicationRef源码分析_前端

InnerZone四方法

NgZone中InnerZone的创建是通过forkInnerZoneWithAngularBehavior完成的,创建过程的简化版如下,其中又能看到很多熟悉的勾子函数。这里简单复习一下这几个勾子的意义:

  • onInvokeTask:zone.js会在初始化的时候将异步方法都Pathc成ZoneTask,从而跟踪异步任务的执行情况的。onInvokeTask就是其中的一个勾子函数,它会在异步任务执行回调的时候触发。
  • onInvokeonInvoke会在我们手动执行zone.run()的时候执行。
  • onHasTask:是针对整个任务队列状态改变的监听,当检测任务队列中有任务进入、或是有任务执行完出队列的时候会被执行。
  • onHandleError:当有异常抛出时被执行

InnerZone对异步任务的控制精华基本上就全部浓缩在这几个勾子函数中了,与此同时,为了更好地配合对异步任务的跟踪,NgZone中还定义了很多状态监控字段。只有理清这些字段的含义才能继续往下深入代码。

不熟悉zone.js原理的可以回看一下zone.js由入门到放弃之一和zone.js由入门到放弃之二(链接见文首)

传送门

function forkInnerZoneWithAngularBehavior(zone: NgZonePrivate) {
  zone._inner = zone._inner.fork({
    name: 'angular',
    properties: <any>{'isAngularZone': true},
    onInvokeTask: (...): any => {
      ...
    },
    onInvoke: (...): any => {
      ...
    },
    onHasTask: (...): any => {
      ...
    },
    onHandleError: (...): any => {
      ...
    },
  });
}

InnerZone五状态

接下来这几个状态属性会贯穿在后面的源码分析的全部过程中,我们也会通过对这几个状态的跟踪了解一下InnerZone事件跟踪的原理。

  • hasPendingMacrotasks: boolean 队列中是否有待执行的宏任务
  • hasPendingMicrotasks: boolean 队列中是否有待执行的微任务
  • _nesting: number 队列中待执行任务的个数
  • isStable: boolean 当任务队列中既没有待执行的宏任务,也没有待执行的微任务时,isStable为ture,表示当前是个稳定的状态。反之则代表非稳定状态。
  • lastRequestAnimationFrameId: number 这个状态有些特别,它是一个延时器,后面会展开解释。

代码走读

前面在介绍zone.js的时候我们说过,zone.js把异步任务分为MacroTask、MicroTask和Event三种。今天我们就分别把这三种任务都按流程分析一遍。从难易程度上看,MacroTask最简单,Event相对最复杂。接下来,我们就按照这个顺序讲解。

zone.js由入门到放弃之五——NgZone & ApplicationRef源码分析_前端_02

MacroTask

之前在zone.js由入门到放弃之三中,详细介绍过zone.js对setTimeout的Patch过程,如果不了解具体过程的强烈建议先浏览一下那篇文章。

这一次,我们还是通过个setTimeout事件来跟踪NgZone的处理过程,测试代码很简单,如下所示。

export class AppComponent implements OnInit {
  title = 'ngzone-process';

  ngOnInit(): void {
    setTimeout(() => {
      console.log('[setTimeout] run in next 5s');
    }, 5000);
  }

  ngDoCheck() {
    console.log('rendering...');
  }

}

因为zone.js可以感知到任务队列的变化情况,所以当setTimeout执行时,它可以知道当前有一个宏任务来了,同时会触发onHasTask勾子。

onHasTask

onHasTask"检测"到有宏任务到来时,会把hasPendingMacrotasks设置为true。

传送门

onHasTask:
(delegate: ZoneDelegate, current: Zone, target: Zone, hasTaskState: HasTaskState) => {
  delegate.hasTask(target, hasTaskState);
  if (current === target) {
    // ...
    } else if (hasTaskState.change == 'macroTask') {
      zone.hasPendingMacrotasks = hasTaskState.macroTask;
    }
  }
},

此时,NgZone中的几个状态值大概是这个样子的,hasPendingMacrotasks变为true,表示当前有一个待执行的MacroTask。

接下来,zone.js会通过调用scheduleFn,并把封装后的回调函数放在Timer队列中等待时钟到达。

hasPendingMacrotasks

hasPendingMicrotasks

_nesting

isStable

lastRequestAnimationFrameId

true

false

0

true

-1

onInvokeTask

当时钟到达以后,事件循环会把封装后的回调函数放在任务队列中等待执行。当执行到回调时,回调会触发task.invoke函数,接下来就会唤醒onInvokeTask勾子函数。

传送门

onInvokeTask:
(delegate: ZoneDelegate, current: Zone, target: Zone, task: Task, applyThis: any,
 applyArgs: any): any => {
  try {
    onEnter(zone);
    // 执行真正的回调 

标签:ApplicationRef,zone,js,NgZone,任务,源码,组件,执行
From: https://blog.51cto.com/u_16152776/7528554

相关文章

  • Vue源码学习(七):合并生命周期(混入Vue.Mixin)
    好家伙, 1.使用场景现在来,来想一下,作为一个使用Vue的开发者,假设现在我们要使用created(),我们会如何使用1.1. .vue文件中使用<template><div><h1>{{message}}</h1></div></template><script>exportdefault{created(){this.message='......
  • 想查看某些网站源码,结果发现网站F12被禁用,怎么解决?
    当我们访问某些网站的时候,发现网站是禁用了F12和右键功能的。比如想保存网页上的一些文字或图片等,新手不知道怎么破除。下面分享给大家几种方法:1、打开网页后,鼠标点进浏览器地址栏,再按F12键,就可以用了。2、打开网页后,鼠标点进浏览器地址栏,再按快捷键Ctrl+U,就可以用了。3、可以......
  • DRF之分页类源码分析
    【一】分页类介绍DjangoRESTframework(DRF)是一个用于构建WebAPI的强大工具,它提供了分页功能,使你能够控制API响应的数据量。在DRF中,分页功能由分页类(PaginatorClass)来管理。【二】内置分页类在DRF中,分页类通常位于rest_framework.pagination模块中,它们用于分割长列表或......
  • DRF之排序类源码分析
    【一】排序类介绍在DjangoRESTframework(DRF)中,排序类用于处理API端点的排序操作,允许客户端请求按特定字段对数据进行升序或降序排序。排序类是一种特殊的过滤类DRF提供了内置的排序类,并且你也可以自定义排序类以满足特定的需求。【二】内置排序类OrderingFilterrest_f......
  • DRF之JWT签发Token源码分析
    【一】JWT介绍JWT(JSONWebToken)是一种用于身份认证和授权的开放标准(RFC7519)。它基于JSON格式定义了一种安全的令牌,用于在客户端和服务器之间传输信息。【二】JWT三段式JWT(JSONWebToken)是一种用于身份认证和授权的开放标准(RFC7519)。它基于JSON格式定义了一种安全的令......
  • 短视频app源码,Android TextView文字,删除线以及下划线
    短视频app源码,AndroidTextView文字,删除线以及下划线1、删除线 TextViewtextview=(TextView)view.findViewById(R.id.textviewk);textview.getPaint().setFlags(Paint.STRIKE_THRU_TEXT_FLAG);​2、下划线 TextViewtextview=(TextView)view.findViewById(R.id.textvi......
  • 源码编译Unreal Engine升级到5.3
    1.更新代码gitfetchorigin2.检出5.3.0releasegitcheckout5.3.0release3.安装依赖Setup.bat4.生成项目文件GenerateProjectFiles.bat5.打开UE5.sln编译配置:"DevelopmentEditor","Win64"......
  • PACS医学影像处理系统源码-虚拟内窥镜 三维重建技术
    PACS系统与医院HIS实现双向数据交换,自动从HIS系统获得病人基本信息、检查预约请求,自动向HIS系统传送预约请求接受、检查费用发生信息,接受来自HIS系统的检查结果查询和图像数据检索。医院医学影像PACS系统源码,集成三维影像后处理功能,包括三维多平面重建、三维容积重建、三维表面重建......
  • Glide源码阅读之适配器模式【ArrayAdapterInterface<T>】
    定义菜鸟教程介绍意图:将一个类的接口转换成客户希望的另外一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。主要解决:主要解决在软件系统中,常常要将一些"现存的对象"放到新的环境中,而新环境要求的接口是现对象不能满足的。何时使用:1、系统需要使......
  • Glide源码阅读之策略模式2【DownsampleStrategy】
    策略模式二DownsampleStrategy包路径:com.bumptech.glide.load.resource.bitmap.DownsampleStrategy指示对图像进行下采样时使用的算法。DownsampleStrategy不提供任何关于输出大小的保证。行为将不同,取决于ResourceDecoder使用的策略和Android版本的代码运行。使用DownsampleStrat......