本文同步自我得博客:http://www.joeray61.com前端
不少作前端的朋友應該都據說過Promise
(或者Deferred
)對象,今天我就講一下我對Promise
的認識web
Promise
是CommonJS
的規範之一,擁有resolve
、reject
、done
、fail
、then
等方法,可以幫助咱們控制代碼的流程,避免函數的多層嵌套。現在異步在web開發中愈來愈重要,對於開發人員來講,這種非線性執行的編程會讓開發者以爲難以掌控,而Promise
可讓咱們更好地掌控代碼的執行流程,jQuery
等流行的js庫都已經實現了這個對象,年末即將發佈的ES6
也將原生實現Promise
ajax
想象這樣一個場景,兩個異步請求,第二個須要用到第一個請求成功的數據,那麼咱們代碼能夠這樣寫編程
ajax({ url: url1, success: function(data) { ajax({ url: url2, data: data, success: function() { } }); } });
若是繼續下去在回調函數中進行下一步操做,嵌套的層數會愈來愈多。咱們能夠進行適當的改進,把回調函數寫到外面數組
function A() { ajax({ url: url1, success: function(data) { B(data); } }); } function B(data) { ajax({ url: url2, success: function(data) { ...... } }); }
即便是改寫成這樣,代碼仍是不夠直觀,可是若是有了Promise對象,代碼就能夠寫得很是清晰,一目瞭然,請看異步
new Promise(A).done(B);
這樣函數B就不用寫在A的回調中了函數
目前的ES
標準中還未支持Promise
對象,那麼咱們就本身動手,豐衣足食吧。思路大體是這樣的,用2個數組(doneList
和failList
)分別存儲成功時的回調函數隊列和失敗時的回調隊列this
state
: 當前執行狀態,有pending
、resolved
、rejected
3種取值url
done
: 向doneList
中添加一個成功回調函數prototype
fail
: 向failList
中添加一個失敗回調函數
then
: 分別向doneList
和failList
中添加回調函數
always
: 添加一個不管成功仍是失敗都會調用的回調函數
resolve
: 將狀態更改成resolved
,並觸發綁定的全部成功的回調函數
reject
: 將狀態更改成rejected
,並觸發綁定的全部失敗的回調函數
when
: 參數是多個異步或者延遲函數,返回值是一個Promise兌現,當全部函數都執行成功的時候執行該對象的resolve
方法,反之執行該對象的reject
方法
下面是個人具體實現過程:
var Promise = function() { this.doneList = []; this.failList = []; this.state = 'pending'; }; Promise.prototype = { constructor: 'Promise', resolve: function() { this.state = 'resolved'; var list = this.doneList; for(var i = 0, len = list.length; i < len; i++) { list[0].call(this); list.shift(); } }, reject: function() { this.state = 'rejected'; var list = this.failList; for(var i = 0, len = list.length; i < len; i++){ list[0].call(this); list.shift(); } }, done: function(func) { if(typeof func === 'function') { this.doneList.push(func); } return this; }, fail: function(func) { if(typeof func === 'function') { this.failList.push(func); } return this; }, then: function(doneFn, failFn) { this.done(doneFn).fail(failFn); return this; }, always: function(fn) { this.done(fn).fail(fn); return this; } }; function when() { var p = new Promise(); var success = true; var len = arguments.length; for(var i = 0; i < len; i++) { if(!(arguments[i] instanceof Promise)) { return false; } else { arguments[i].always(function() { if(this.state != 'resolved'){ success = false; } len--; if(len == 0) { success ? p.resolve() : p.reject(); } }); } } return p; }
目前只是實現了Promise
的基礎功能,但仍然還有沒法處理的狀況,例如要實現3個或3個以上的異步請求的串行,目前個人Promise
沒有辦法支持new Promise(A).then(B).then(C)
這樣的形式,jQuery
在1.7的版本中爲Deferred
(Promise
)對象實現了pipe
函數,能夠經過這個函數實現上述功能,代碼爲$.Deferred(A).pipe(B).then(C)
,我嘗試去讀了jQuery
這部分的代碼,可是沒能讀懂,但願有大神可以給一些實現思路