學習ng2,從zonejs開始(非官方翻譯) ----angular2系列(一)


Zone是什么

  官方解釋:zone.js為JavaScript提供了執行上下文,可以在異步任務之間進行持久性傳遞。

最開始我一直沒理解到這句話,學習過程中我也因為自己的一些失誤而一直糾結徘徊,情況是這樣的:

  首先我在本地用npm安裝了zone.js,然后我就打開了zone.js的github ———— zoneJs

這一切都很正常,然后看着readme,跟着demo寫下去。下面這樣:

 

然后問題來了,當我運行的時候,結果根本就不是官方顯示的那樣,我打開調試器,發現全局根本沒有 window.zone ,卻只有window.Zone,

難道是需要new一個?好吧,我new一個。結果還是不對。 好吧,我去看源碼,發現原型根本就沒有beforeTask,afterTask,而后看了很久源碼,

發現run和fork方法的執行邏輯, 根本就不像是官方教程那樣。

最后我終於找到問題了:

 

是版本問題,我看的教程是0.5版本,看的源碼確是0.6,本地安裝的版本也是默認最新的0.6。

好吧,我承認我英文不好,沒看到DEPRECATED 這個單詞。

安裝0.5,那么這個問題解決了。以后小心...

 

言歸正傳, 我們在demo中去理解:

zone.fork().run(function () {
  zone.inTheZone = true;

  setTimeout(function () {
    console.log('in the zone 1: ' + !!zone.inTheZone);
  }, 0);
});

console.log('in the zone 2: ' + !!zone.inTheZone);

//console
//'in the zone 2: false'
//'in the zone 1: true'

在demo的基礎上,我加上了數字編號 'in the zone ' + '1' or '2',  當然他們的執行順序,沒什么問題。問題就是為什么第一次輸出是false?

執行run的時候,zone.inTheZone已經變成true了,這個全局對象的屬性應該已經是true了啊!

readme下面還有一句話:Note that the function delayed by setTimeout stays inside the zone

延遲方法已經停留在zone內部,這是什么意思?這時候我又改變了一下代碼:

zone.fork().run(function () {
        zone.inTheZone = true;
        console.log(zone);
        console.log('1: ' + !!zone.inTheZone);
        setTimeout(function () {
          console.log(zone);
          console.log('2: ' + !!zone.inTheZone);
        }, 0);
      });
console.log(zone);
console.log('3: ' + !!zone.inTheZone);

結果:

 

注意zone的 id , 全局zone原來一直在變化, 他們的父子關系是如下:父->子,id:1 -> id:2 -> id:3

全局zone最開始默認id為1。

zone.fork.run的時候,zone就創建了一個新zone任務,id為2

執行setTimeout的時候,又創建了一個id為3。

不管運行什么任務,其實全局zone都在變化,所有任務都在全局zone下執行了。

這就是官方說的:zone.js采用猴子補丁(Monkey-patched)的暴力方式將JavaScript中的異步任務都包裹了一層,使得這些異步任務都將運行在zone的上下文中。

 

好吧,雖然說zone在變化,為什么第一次輸出是false,現在解釋可能就簡單的多了。還得看下源碼:

源碼告訴我們:在執行當前zone任務的時候,全局zone指向當前任務的zone對象,執行完畢后全局zone還原到前一個zone任務。

 

那么,執行run的時候,全局zone是id2的任務,執行完畢后 id2的zone的inTheZone屬性變成true,全局zone又變成id1的zone對象,

而后馬上輸出了 id1 的 inTheZone 屬性,這個時候 id1 並沒有定義inTheZone,所以是false。

最后執行了 id3 的任務,為什么又輸出是true呢,現在只有 id2 的 inTheZone 才會是true啊!

原因是zone會繼承父zone,如圖:

 

這樣這個輸出結果為什么是這樣就算搞清楚了。

 

但是它又是如何給setTimeout添加zone任務的呢,因為run執行時並沒有辦法執行延遲操作,異步操作會被添加到瀏覽器的事件隊列,在下一次事件循環(event loops)中才會被執行。

setTimeout怎么被zone給捕獲的呢。這也是zoneJs比較核心的一個地方:

zone修改了原生setTimeout,我們在控制器里輸入setTimeout,結果如下:

function() {
    return global.zone[setName].apply(global.zone, arguments);
}

當然被修改的還有下面這些延遲事件(截圖自源碼):

所有延遲事件都將被zone捕獲。

 

zone還提供了執行前后的鈎子函數(hook):

  • onZoneCreated:產生一個新的zone對象時的鈎子函數。zone.fork也會產生一個繼承至基類zone的新zone,形成一個獨立的zone上下文;
  • beforeTask:zone Task執行前的鈎子函數;
  • afterTask:zone Task執行完成后的鈎子函數;
  • onError:zone運行Task時候的異常鈎子函數;

demo如下:

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

      zone.fork(profilingZone).run(function(){
        console.log(profilingZone.time());
        setTimeout(function(){console.log(profilingZone.time())}, 200);

      });

/***console***/
//
beforeTask
//0ms
//afterTask

//beforeTask
//1.8ms
//
afterTask

這些鈎子函數能幫助我們,任務前后攔截並做一些想要的操作,不管是延遲或不延遲的任務都將被攔截。

 

zoneJs官網已經不推薦0.5版本了,但是zone0.6幾乎算沒有文檔。

readme上的: See the new API here

打開這個here,看起來確實也很難理解

zonejs 0.6改動較大,封裝性很強,寫法變化較大,還有待研究

目前ng2已經在升級0.6了,最終修改完畢后,到底會是什么樣子,還不得知,目前我看到的0.6的源碼里,好像已經沒有beforeTask這些鈎子函數了。

總之0.6的代碼太難以理解了。我沒怎么看懂,它可以做什么。

目測ng2要發布正式版,還需要時間。

當然這篇博客還是參考了,破狼的文章 zone.js - 暴力之美

非常感謝他為ng社區做出的貢獻!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM