promise
javascript
异步
这几天在看朴灵的深入浅出nodejs,看到异步编程的解决方案这一章时,卡在了promise这个地方。心中的念头就是自己动手写一个promise才好,于是就开始在网上找资料。
简介,这些代码首先是发表在Stack Overflow,是希望你能从中学习如何使用javascript实现一个promise,你将会更好的理解promise是如何的实现的。
状态机
由于promise仅仅是一个状态机,我们必须从我们将会用到的状态信息开始考虑。
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:
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
。我们用到了一系列的辅助函数,如下:
/**
* 检查一个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。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。