promise
javascript
異步
這幾天在看樸靈的深刻淺出nodejs,看到異步編程的解決方案這一章時,卡在了promise這個地方。心中的念頭就是本身動手寫一個promise纔好,因而就開始在網上找資料。javascript
簡介,這些代碼首先是發表在Stack Overflow,是但願你能從中學習如何使用javascript實現一個promise,你將會更好的理解promise是如何的實現的。html
因爲promise僅僅是一個狀態機,咱們必須從咱們將會用到的狀態信息開始考慮。java
var PENDDING = 0; var FULFILLED = 1; var REJECTED = 2; function Promise(){ //保存的狀態能夠爲PENDDING,FULFILLED和REJECTED var state = PENDDING; //一旦FULFILLED或者REJECTED保存爲value或者err var value = null; //保存成功或者失敗的處理程序 var handlers = [] }
第二步,讓咱們考慮下面兩種可能出現的情形,fulfilling和rejecting:node
var PENDDING = 0; var FULFILLED = 1; var REJECTED = 2; function Promise(){ //保存的狀態能夠爲PENDDING,FULFILLED和REJECTED var state = PENDDING; //一旦FULFILLED或者REJECTED保存爲value或者err var value = null; //保存成功或者失敗的處理程序 var handlers = [] function fullfill(result){ state = FULFILLED; value = result; } function reject(error){ state = REJECTED; value = error; } }
上面這些給了咱們較低等級的變換,可是咱們還能夠考慮額外更高級的叫作resolve的
變換。編程
var PENDDING = 0; var FULFILLED = 1; var REJECTED = 2; function Promise(){ //保存的狀態能夠爲PENDDING,FULFILLED和REJECTED var state = PENDDING; //一旦FULFILLED或者REJECTED保存爲value或者err var value = null; //保存成功或者失敗的處理程序 var handlers = [] function fulfill(result){ state = FULFILLED; value = result; } function reject(error){ state = REJECTED; value = error; } function resolve(result){ try{ var then = getThen(result); if(then){ doResolve(then.resolve(result),resolve,reject) return } fullfill(result) }catch(e){ reject(e) } } }
注意不管傳入resolve的是一個promise對象仍是一個普通值,若是它是一個promise對象,等待他完成。一個promise對象不會進入fulfilled狀態若是它還包含一個promise對象的話,所以咱們將要暴露出的resolve
函數強於內部的fulfill
。咱們用到了一系列的輔助函數,以下:promise
/** * 檢查一個value是不是一個promise對象,若是是,返回那個promise的then方法 * * @param {promise|any} value * @return {Function|null} */ function getThen(value){ var t = typeof value; if(value && (t === 'object'||t === 'function')){ var then = value.then; if(typeof then === 'function'){ return then } } return null } /** * 建立一個對潛在行爲的處理方法而且保證onFulfilled和onRejected只被調用一次 * 不對異步作保證 * * @param {Function} fn A resolver function that may not be trusted * @param {Function} onFulfilled * @param {Function} onRejected */ function doResolve(fn,onFulfilled,onRejected){ var done = false; try{ fn(function(value){ if(done) return done = true onFulfilled(value) },function(reason){ if(done) return done = true onRejected(reason) }) }catch(ex){ if(done) return done = true onRejected(ex) } }
咱們如今已經完成了內部的狀態機,但同時咱們還須要暴露一個處理或者觀察該promise的方法,咱們來增長一個處理promise的途徑:異步
var PENDDING = 0; var FULFILLED = 1; var REJECTED = 2; function Promise(fn){ //保存的狀態能夠爲PENDDING,FULFILLED和REJECTED var state = PENDDING; //一旦FULFILLED或者REJECTED保存爲value或者err var value = null; //保存成功或者失敗的處理程序 var handlers = [] function fulfill(result){ state = FULFILLED; value = result; } function reject(error){ state = REJECTED; value = error; } function resolve(result){ try{ var then = getThen(result); if(then){ doResolve(then.resolve(result),resolve,reject) return } fullfill(result) }catch(e){ reject(e) } } doResolve(fn,resolve,reject) }
如你所見,咱們複用了deResolve
由於咱們有另外一個不被信任的處理器,fn
函數能夠調用resolve
和reject
屢次,甚至能夠拋出異常,咱們如今要作的是保證promise只執行或者拒絕一次,而後不在變換爲其餘的狀態。異步編程
.done
方法)咱們如今有一個已經完成的狀態機,可是咱們仍然沒有觀察他的變化。咱們最終要完成的是實現.then
,可是因爲.done
簡單不少因而咱們就先實現它。
咱們如今要實現promise.done(onFulfilled,onRejected)
要知足如下的功能:
- onFulfilled
和onRejected
中一個被調用
- 只被調用一次
- 在下一個tick(即.done
方法返回後)時才被調用
- 它將會被調用無論promise是在咱們調用.done
以前或者以後被處理函數
var PENDDING = 0; var FULFILLED = 1; var REJECTED = 2; function Promise(fn){ //保存的狀態能夠爲PENDDING,FULFILLED和REJECTED var state = PENDDING; //一旦FULFILLED或者REJECTED保存爲value或者err var value = null; //保存成功或者失敗的處理程序 var handlers = [] function fulfill(result){ state = FULFILLED; value = result; handlers.forEach(handle); handlers = null } function reject(error){ state = REJECTED; value = error; handlers.forEach(handle); handlers = null } function resolve(result){ try{ var then = getThen(result); if(then){ doResolve(then.resolve(result),resolve,reject) return } fullfill(result) }catch(e){ reject(e) } } function handle(handler){ if(state === PENDDING){ handlers.push(handler) }else{ if(state === FULFULLIED && typeof handler.onFulfilled === 'function'){ handler.onFulfilled(value); } if(state === REJECTED && typeof handler.onRejected === 'function'){ handler.onRejected(value); } } } this.done = function(onFulfilled,onRejected){ //保證異步執行 setTimeout(function(){ handle({ onFulfilled : onFulfilled, onRejected : onRejected }) },0) } doResolve(fn,resolve,reject) }
咱們得肯定Promise被Resolved或者Rejected後處理程序能夠獲得通知,僅僅是在進入下一個tick時作這些。學習
.then
方法)如今咱們已經完成了.done
方法,咱們能夠很相似的實現.then
方法,只是要多構建一個Promise方法。
this.then = function(onFulfilled,onRejected){ var self = this; return new Promise(function(resolve,Reject){ return self.done(function(resolve){ if(typeof onFulfilled === 'function'){ try{ resolve(onFulfilled(result)) }catch(e){ reject(e) } }else{ return resolve(result) } },function(error){ if(typeof onRejected === 'function'){ try{ reject(onRejected(error)) }catch(e){ reject(e) } }else{ reject(error) } }) }) }
以上翻譯自Promise Implementing。