不經意看到了一個構思很是驚人的異步流程控制庫,發出來分享下html
http://cho45.stfuawsc.com/jsdeferred/ jquery
關於CommonJS Promises請看另外一個異步庫 http://www.cnblogs.com/aaronjs/p/3168588.htmlweb
整個代碼很是簡潔,易用,不過呢是小日本寫的東西…數組
API手冊:瀏覽器
加載jsdeferred定義延遲對象。爲方便起見,咱們用Deferred.define()方法把接口導出到全局做用於中dom
Deferred.define();
經過這樣作,你就能使用如 next(), loop(), call(), parallel() and wait() 這樣的全局函數方法,讓咱們抒寫一些異步的流程異步
next(function () { alert("Hello!"); return wait(5); }). next(function () { alert("World!"); });
這個流程中,開始會彈出 「Hello」,而後過5秒接着會彈出 「world」函數
Deferred.next(function () { alert("Hello!"); return Deferred.wait(5); }). next(function () { alert("World!"); });
上面是抒寫同上oop
我的分析:post
用Deferred.define()方法,無疑污染了全局做用域,入侵性太強了,跟mootools,prototype同樣, 不過好處嘛,很明顯,簡單易用了
還好JSDeferred也提供了無侵入的寫法
亮源碼:
Deferred.define = function (obj, list) { if (!list) list = Deferred.methods; if (!obj) obj = (function getGlobal() { return this })(); for (var i = 0; i < list.length; i++) { var n = list[i]; obj[n] = Deferred[n]; } return Deferred; };
能夠傳入一個對象,用做上下文
var o = {}; //定義一個對象 Deferred.define(o);//把Deferred的方法加持到它上面,讓o成爲一個Deferred子類。 o.next(function(){ /* 處理 */ })
Deferred.methods = ["parallel", "wait", "next", "call", "loop", "repeat", "chain"];
next方法
根據源碼看來Deferred.next其實就是一個靜態方法
Deferred.next = Deferred.next_faster_way_readystatechange || Deferred.next_faster_way_Image || Deferred.next_tick || Deferred.next_default;
顯而易見,next方法是有四種選擇優先級,爲何要這樣呢?
我是基於webkit的遊覽器,因此咱們就直接看Deferred.next_faster_way_Image
// Modern Browsers var d = new Deferred(); var img = new Image(); var handler = function () { d.canceller(); d.call(); }; img.addEventListener("load", handler, false); img.addEventListener("error", handler, false); d.canceller = function () { img.removeEventListener("load", handler, false); img.removeEventListener("error", handler, false); }; img.src = "data:image/png," + Math.random(); if (fun) d.callback.ok = fun; return d;
流程:
因而可知
next(fn).next(fn).next(fn)
其實就是
第一個 next() Deferred.next_faster_way_Image () 返回 d
第二個 next() d.next()
第二個next(),其實就是實例Deferred類的原型方法了
具體咱們看
next: function (fun) { return this._post("ok", fun) },
_post: function (okng, fun) { this._next = new Deferred(); this._next.callback[okng] = fun; return this._next; },
看到_post方法,就有撥開雲霧見月明的感受了
其實內部會有從新生成一個 Deferred對象掛到父實例的 next上,在綁定回調..
如此依次循環處理
因此初始化的時候其實內部就生成了這麼一個隊列
_next 上都掛着下一個隊列處理
此時都是在初始化準備好的了,在執行的時候 Image 在成功回調中,咱們調用了 d.call();
執行實例的call方法
call: function (val) { return this._fire("ok", val) },
_fire: function (okng, value) { var next = "ok"; try { value = this.callback[okng].call(this, value); } catch (e) { next = "ng"; value = e; if (Deferred.onerror) Deferred.onerror(e); } if (Deferred.isDeferred(value)) { value._next = this._next; } else { if (this._next) this._next._fire(next, value); } return this; }
總結:
構思很特別,把每次鏈式的回調掛到內部的next子屬性中,在處理上也保持了一條線的引用關係,而不是常規的用數組的方式存起來
固然上面僅僅只是同步方法的處理分析,也不是標準的遵循CommonJS Promises規範去抒寫的