Angular zone 学习笔记

举报
Jerry Wang 发表于 2022/05/14 19:09:24 2022/05/14
【摘要】 https://blog.thoughtram.io/angular/2016/01/22/understanding-zones.html假设有这三个函数:foo();bar();baz();function foo() {...}function bar() {...}function baz() {...}要度量其运行时间:var start, time = 0; time...

https://blog.thoughtram.io/angular/2016/01/22/understanding-zones.html

假设有这三个函数:

foo();
bar();
baz();

function foo() {...}
function bar() {...}
function baz() {...}

要度量其运行时间:

var start,
    time = 0;
    timer = performance ? performance.now : Date.now;

// start timer
start = timer();
foo();
bar();
baz();
// stop timer
time = timer() - start;
// log time in ms
console.log(Math.floor(time*100) / 100 + 'ms');

然而,如果这些函数是异步执行的函数呢?那么下列的时间度量代码,计算出来的duration就不准确了:

function doSomething() {
  console.log('Async task');
}

// start timer
start = timer();
foo();
setTimeout(doSomething, 2000);
bar();
baz();
// stop timer
time = timer() - start;

什么是Angular的zone?

Zones can perform an operation - such as starting or stopping a timer, or saving a stack trace - each time that code enters or exits a zone. They can override methods within our code, or even associate data with individual zones.

zone可以在一段代码进入或者离开一个zone的时候,执行一个操作,比如开启或者关闭计时器,或者保存一个堆栈跟踪。

Zones are actually a language feature in Dart.

Zone实际上是编程语言Dart的一个特性。Dart编译之后的代码也是JavaScript,所以我们可以直接在JavaScript里实现Zone的特性。

Angular项目里通常都有zone.js的依赖:

导入zone.js依赖之后,我们获得了zone全局对象的访问权。可以使用其run方法,将某个函数放入一个zone里执行:

function main() {
  foo();
  setTimeout(doSomething, 2000);
  bar();
  baz();
}

zone.run(main);

Zones can perform an operation each time our code enters or exits a zone.

支持fock操作:

var myZone = zone.fork();

myZone.run(main);

fock的时候可以指定一些参数,定制fock出来的zone的行为:

var myZoneSpec = {
  beforeTask: function () {
    console.log('Before task');
  },
  afterTask: function () {
    console.log('After task');
  }
};

var myZone = zone.fork(myZoneSpec);
myZone.run(main);

// Logs:
// Before task
// After task
// Before task
// Async task
// After task

It turns out that there are a few other hooks. In fact, those aren’t just hooks, but monkey-patched methods on the global scope.

全局scope里还存在称为monke-patched的方法。

when we call setTimeout() we actually call Zone.setTimeout(), which in turn creates a new zone using zone.fork() in which the given handler is executed.

当我们调用setTimeout时,我们实际上调用的是Zone.setTimeout, 后者会使用zone.fork(),创建新的zone,而setTimeout里的函数,就运行在这个新fork出来的zone里面。

And that’s why our hooks are executed as well, because the forked zone in which the handler will be executed, simply inherits from the parent zone.

而hook执行两次的原因,是因为函数运行于fork出来的zone里面,而后者继承了parent zone的hook.

Zone.js重载了下列方法,并且以hook的方式提供给应用开发人员使用:

  • Zone.setInterval()
  • Zone.alert()
  • Zone.prompt()
  • Zone.requestAnimationFrame()
  • Zone.addEventListener()
  • Zone.removeEventListener()

We might wonder why methods like alert() and prompt() are patched as well. As mentioned earlier, those patched methods are hooks at the same time. We can change and extend them by forking a zone exactly the same way we did with beforeTask and afterTask. This turns out to be super powerful, because we can intercept calls to alert() and prompt() and change their behaviour when we write tests.

类似alert和prompt方法和其他方法一样同时被patch,在fork一个新zone时,可以传入我们自己的实现进去,在写单元测试代码时尤其有用。

用于度量一段异步执行代码执行时间的profilingZone的实现源代码:

var profilingZone = (function () {
  var time = 0,
      timer = performance ?
                  performance.now.bind(performance) :
                  Date.now.bind(Date);
  return {
    beforeTask: function () {
      this.start = timer();
    },
    afterTask: function () {
      time += timer() - this.start;
    },
    time: function () {
      return Math.floor(time*100) / 100 + 'ms';
    },
    reset: function () {
      time = 0;
    }
  };
}());

使用方式:

zone
  .fork(profilingZone)
  .fork({
    '+afterTask': function () {
      console.log('Took: ' + zone.time());
    }
  })
  .run(main);
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。