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):
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社區作出的貢獻!