可移步 http://donglegend.com/2016/09/11/promise%E5%8E%9F%E7%90%86%E6%8E%A2%E7%A9%B6/ 觀看
Promise是個什么玩意,大家都知道,度娘告訴我,以同步方式書寫異步,解決回調地獄。。。
狀態機
早聞Promise的大名,簡單介紹,根據狀態改變來執行相應處理函數。
Promise的狀態極其簡單,只有 “pending”, “resolved”, “rejected”三種狀態
然后就是如何實現的問題,最關鍵的當然是監聽到狀態的更新,然后才能做出回應,那么如何知道狀態變了呢?
最初單純的我開了一個腦洞,有以下想法:
- 寫一個定時器不斷查詢狀態值,如果有變化,那么執行回調
- 利用ES5的 Object.defineProperty(obj, prop, descriptor)來追蹤狀態變化。
- 直接修改狀態為指定值,然后接着執行回調
嗚嗚嗚,有時候總會犯傻不是,上面第一種維護一個定時器,效率低下;第二種把狀態變得很麻煩和復雜;
其實很多事情之所以復雜,是因為我們想的太多。
Promise根本沒那么復雜,就三個狀態,搞毛線定時器,狀態跟蹤。
利用觀察者模式,只需要通過特定書寫方式注冊對應狀態的事件處理函數,然后更新狀態,調用注冊過的處理函數即可。這個特定方式就是 then ,done ,fail, always…等方法;更新狀態觸發時機就是resolve, reject方法。
簡單實現
理論分析:
- 寫一個類對象,維護一個 state,值有3種:”pending”, “resolved”, “rejected”
- 通過then done fail always方法注冊回調處理函數
- 通過resolve reject分別更新對應狀態,並且調用注冊函數
代碼如下:
1 /** 2 * [3種狀態] 3 * @type {String} 4 */ 5 6 var PENDING = "pending"; 7 var RESOLVED = "resolved"; 8 var REJECTED = "rejected"; 9 /** 10 * [Promise類實現] 11 * 構造函數傳入一個fn,有兩個參數,resolve:成功回調; reject:失敗回調; 12 * state: 狀態存儲 13 * doneList: 成功處理函數列表 14 * failList: 失敗處理函數列表 15 * done: 注冊成功處理函數 16 * fail: 注冊失敗處理函數 17 * then: 同時注冊成功和失敗處理函數 18 * always: 一個處理注冊到成功和失敗,都會調用 19 * resolve: 更新state為:RESOLVED,並且執行成功處理隊列 20 * reject: 更新state為:REJECTED,並且執行失敗處理隊列 21 */ 22 var Promise = (function (){ 23 function Promise(fn){ 24 this.state = PENDING; 25 this.doneList = []; 26 this.failList = []; 27 this.fn = fn; 28 this.fn(this.resolve.bind(this), this.reject.bind(this)) 29 } 30 31 var p = { 32 done: function (cb){ 33 if(typeof cb == "function") 34 this.doneList.push(cb) 35 return this; 36 }, 37 fail: function(cb){ 38 if(typeof cb == "function") 39 this.failList.push(cb); 40 return this; 41 }, 42 then: function(success, fail){ 43 this.done(success || noop).fail(fail || noop) 44 return this; 45 }, 46 always: function(cb){ 47 this.done(cb).fail(cb) 48 return this; 49 }, 50 resolve: function(){ 51 this.state = RESOLVED; 52 var lists = this.doneList; 53 for(var i = 0, len = lists.length; i<len; i++){ 54 lists[0].apply(this, arguments); 55 lists.shift(); 56 } 57 return this; 58 }, 59 reject: function(){ 60 this.state = REJECTED; 61 var lists = this.failList; 62 for(var i = 0, len = lists.length; i<len; i++){ 63 lists[0].apply(this, arguments); 64 lists.shift(); 65 } 66 return this; 67 } 68 } 69 for(var k in p){ 70 Promise.prototype[k] = p[k] 71 } 72 73 return Promise; 74 })(); 75 76 function noop(){}
使用方式,請到https://github.com/donglegend/MyPromise下載使用
源碼下載