当前位置: 代码网 > it编程>前端脚本>AngularJs > Angular异步执行学习之zone.js使用

Angular异步执行学习之zone.js使用

2024年05月18日 AngularJs 我要评论
什么是 zone ?或许你听说过 angular 使用了zone.js, 但 angular 为什么要使用zone.js, 它能够提供哪些功能呢?今天我们单独写一篇文章聊聊zone.js,关于它在 a

什么是 zone ?

或许你听说过 angular 使用了zone.js, 但 angular 为什么要使用zone.js, 它能够提供哪些功能呢?今天我们单独写一篇文章聊聊zone.js,关于它在 angular 框架中发挥的作用将在下一篇文章讲述。

什么是 zone ? 官方文档是这么解释的:zone 是一个跨多个异步任务的执行上下文。一句话总结来说,zone 在拦截或追踪异步任务方面有着特别强大的能力。

工作原理剖析

下面我们将通过一个示例来展示它的能力,并简单剖析一下背后的工作原理。

<button id="b1">bind error</button>
<button id="b2">cause error</button>
<script>
  function main() {
    b1.addeventlistener('click', bindsecondbutton);
  }
  function bindsecondbutton() {
    b2.addeventlistener('click', throwerror);
  }
  function throwerror() {
    throw new error('aw shucks');
  }
  main();
</script>

这是一个简单的 html 页面。页面加载时会给第一个按钮添加点击事件,其点击事件函数的功能是给第二个按钮添加点击事件,而第二个按钮的点击事件函数功能是抛出一个异常。我们依次点击第一个按钮和第二个按钮,控制台显示如下:

(索引):26 uncaught error: aw shucks
    at htmlbuttonelement.throwerror ((索引):26:13)

zone.js启动

但是如果我们通过zone.js启动运行代码,控制台输出会有什么不同呢,我们先调整启动代码:

zone.current.fork(
      {
        name: 'error',
        onhandleerror: function (parentzonedelegate, currentzone, targetzone, error) {
          console.log(error.stack);
        }
      }
    ).fork(zone.longstacktracezonespec).run(main);

此时控制台输出如下:

error: aw shucks
    at htmlbuttonelement.throwerror ((索引):26:13)
    at zonedelegate.invoketask (zone.js:406:31)
    at zone.runtask (zone.js:178:47)
    at zonetask.invoketask [as invoke] (zone.js:487:34)
    at invoketask (zone.js:1600:14)
    at htmlbuttonelement.globalzoneawarecallback (zone.js:1626:17)
    at ____________________elapsed_571_ms__at__mon_jan_31_2022_20_09_09_gmt_0800_________ (localhost)
    at object.onscheduletask (long-stack-trace-zone.js:105:22)
    at zonedelegate.scheduletask (zone.js:386:51)
    at zone.scheduletask (zone.js:221:43)
    at zone.scheduleeventtask (zone.js:247:25)
    at htmlbuttonelement.addeventlistener (zone.js:1907:35)
    at htmlbuttonelement.bindsecondbutton ((索引):23:10)
    at zonedelegate.invoketask (zone.js:406:31)
    at zone.runtask (zone.js:178:47)
    at ____________________elapsed_2508_ms__at__mon_jan_31_2022_20_09_06_gmt_0800_________ (localhost)
    at object.onscheduletask (long-stack-trace-zone.js:105:22)
    at zonedelegate.scheduletask (zone.js:386:51)
    at zone.scheduletask (zone.js:221:43)
    at zone.scheduleeventtask (zone.js:247:25)
    at htmlbuttonelement.addeventlistener (zone.js:1907:35)
    at main ((索引):20:10)
    at zonedelegate.invoke (zone.js:372:26)
    at zone.run (zone.js:134:43)

通过对比我们知道:不引入zone.js时,我们通过错误调用栈仅仅能够知道,异常是由按钮2的点击函数抛出。而引入了zone.js后,我们不仅知道异常是由按钮2的点击函数抛出,还知道它的点击函数是由按钮1的点击函数绑定的,甚至能够知道最开始的应用启动是main函数触发。这种能够持续追踪多个异步任务的能力在大型复杂项目中异常重要,现在我们来看zone.js是如何做到的吧。

zone.js接管了浏览器提供的异步 api,比如点击事件、计时器等等。也正是因为这样,它才能够对异步操作有更强的控制介入能力,提供更多的能力。现在我们拿点击事件举例,看看它是如何做到的吧。

proto[add_event_listener] = makeaddlistener(nativeaddeventlistener,..)

上述代码中,proto便指的是eventtarget.prototype,也就是说这行代码重新定义了addeventlistener函数。

makeaddlistener函数

我们继续看看makeaddlistener函数做了什么。

function makeaddlistener() {
  ......
  // 关键代码1
  nativelistener.apply(this, arguments);
  ......
  // 关键代码2
  const task = zone.scheduleeventtask(source, ...)
  ......
}

该函数主要做了两件事,一是在自定义函数中执行浏览器本身提供的addeventlistener函数,另外一个就是为每个点击函数安排了一个事件任务,这也是zone.js对异步 api 有强大介入能力的重要因素。

现在我们再回到本文开头的示例中,看看控制台为什么能够输出完整的完整的函数调用栈。刚刚我们分析过了makeaddlistener函数,其中提到它为每个点击函数安排了一个事件任务,也就是zone.scheduleeventtask函数的执行。这个安排事件任务函数最终其实执行的是onscheduletask:

onscheduletask: function (..., task) {
  const currenttask = zone.currenttask;
  let trace = currenttask && currenttask.data && currenttask.data[creationtrace] || [];
  trace = [new longstacktrace()].concat(trace);
  task.data[creationtrace] = trace;
}

文章开头控制台输出的完整的函数调用栈,存储在currenttask.data[creationtrace]里面,它是一个由longstacktrace实例组成的数组。每次有异步任务发生时,onscheduletask函数便把当前函数调用栈存储记录下来,我们看看类longstacktrace的构造器就知道了:

class longstacktrace {
    constructor() {
        this.error = getstacktrace();
        this.timestamp = new date();
    }
}
function getstacktracewithuncaughterror() {
    return new error(error_tag);
}

this.error存储的便是函数调用栈,getstacktrace函数通常调用的是getstacktracewithuncaughterror函数,我们看到 new error大概就能够知道整个调用栈是如何得来的了。

本文分析的只是zone.js能力的一个示例,如果你希望了解更多功能可以参阅官方文档。通过这个示例,希望读者能对zone.js有一个大概的认识,因为它也是 angular 变更检测不可或缺的基石,更多关于angular异步执行zone的资料请关注代码网其它相关文章!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com