Angular zone學習筆記

i042416發表於2021-02-21

blog.thoughtram.io/angu

假設有這三個函式:

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

要度量其執行時間:

var start,
    time = 0;
    timer = performance ? performance.now : Date.now;// start timerstart = timer();foo();bar();baz();// stop timertime = timer() - start;// log time in msconsole.log(Math.floor(time*100) / 100 + 'ms');

然而,如果這些函式是非同步執行的函式呢?那麼下列的時間度量程式碼,計算出來的duration就不準確了:

function doSomething() {
  console.log('Async task');}// start timerstart = timer();foo();setTimeout(doSomething, 2000);bar();baz();// stop timertime = 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的依賴:


Angular zone學習筆記


匯入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裡還存在稱為monkey-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);


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/24475491/viewspace-2758153/,如需轉載,請註明出處,否則將追究法律責任。

相關文章