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。