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

Zone是什麼html

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

最開始我一直沒理解到這句話,學習過程當中我也由於本身的一些失誤而一直糾結徘徊,狀況是這樣的:github

  首先我在本地用npm安裝了zone.js,而後我就打開了zone.js的github ———— zoneJsnpm

這一切都很正常,而後看着readme,跟着demo寫下去。下面這樣:瀏覽器

 

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

難道是須要new一個?好吧,我new一個。結果仍是不對。 好吧,我去看源碼,發現原型根本就沒有beforeTask,afterTask,然後看了好久源碼,異步

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

最後我終於找到問題了:函數

 

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

好吧,我認可我英文很差,沒看到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社區作出的貢獻!

相關文章
相關標籤/搜索