淺談Javascript中Promise對象的實現


https://segmentfault.com/a/1190000000684654

What?

PromiseCommonJS的規范之一,擁有resolverejectdonefailthen等方法,能夠幫助我們控制代碼的流程,避免函數的多層嵌套。如今異步在web開發中越來越重要,對於開發人員來說,這種非線性執行的編程會讓開發者覺得難以掌控,而Promise可以讓我們更好地掌控代碼的執行流程,jQuery等流行的js庫都已經實現了這個對象,年底即將發布的ES6也將原生實現Promise

Why

想象這樣一個場景,兩個異步請求,第二個需要用到第一個請求成功的數據,那么我們代碼可以這樣寫

    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的回調中了

How

目前的ES標准中還未支持Promise對象,那么我們就自己動手,豐衣足食吧。思路大致是這樣的,用2個數組(doneListfailList)分別存儲成功時的回調函數隊列和失敗時的回調隊列

  • state: 當前執行狀態,有pendingresolvedrejected3種取值

  • done: 向doneList中添加一個成功回調函數

  • fail: 向failList中添加一個失敗回調函數

  • then: 分別向doneListfailList中添加回調函數

  • 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; }

Improve

目前只是實現了Promise的基礎功能,但仍然還有無法處理的情況,例如要實現3個或3個以上的異步請求的串行,目前我的Promise沒有辦法支持new Promise(A).then(B).then(C)這樣的形式,jQuery在1.7的版本中為Deferred(Promise)對象實現了pipe函數,可以通過這個函數實現上述功能,代碼為$.Deferred(A).pipe(B).then(C),我嘗試去讀了jQuery這部分的代碼,但是沒能讀懂,希望有大神能夠給一些實現思路


免責聲明!

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



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