Promise实现代码分析
全是去尝试理解别人是怎么实现promise的,感觉下面这两个链接的Promise实现比较好。
实现1 实现2
实现2的配图以及讲解更细致一点,如果能跟着作者举的例子走一遍,应该能够理解为什么可以then().then().then(),以及理解为啥resolve(Promise)的状态为啥是由参数的promise的状态来决定的,也能理解resolve(value)的参数是如何传递给后续的通过then注册的function的。但是30分钟有点少,犹犹豫豫,纠结得看了好久。
相对而言,实现1的较为完整,实现2的某些东西只是提到了,但是没提供实现。比如resolve/reject都只能调用一次。
实现1
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)
}
}
var promise = new Promise(fn);
fn是创建promise传入的参数,它是一个function,在创建Promise的过程中需要被调用。
这个fn有两个参数,都是function,前面一个是在fn按照得到了正常的结果之后调用的,那么then注册的onfulfilled的方法就会在完成之后调用。另外一个就是fn遇到了意料之外的结果,相应的就会调用then注册的onrejected方法。
doResolve的方法就是让fn只能调用一次resolve或者一次reject方法,即只能改变promise的状态一次。
this.done = function (onFulfilled, onRejected) {
// ensure we are always asynchronous
setTimeout(function () {
handle({
onFulfilled: onFulfilled,
onRejected: onRejected
});
}, 0);
}
这个done方法主要是把注册的方法加入到自己这个Promise的回调列表里面。同时为了保证通过then方法注册的function,都要在resolve之后才能调用,用了setTimeout来保证这一点(实现2是这么说的,虽然是在不同的地方用setTimeout)。
function handle(handler) {
if (state === PENDING) {
handlers.push(handler);
} else {
if (state === FULFILLED &&
typeof handler.onFulfilled === 'function') {
handler.onFulfilled(value);
}
if (state === REJECTED &&
typeof handler.onRejected === 'function') {
handler.onRejected(value);
}
}
}
handle这个方法,比实现2的方法要简单一点,因为相关的逻辑在then方法里面体现了。
这个其实就是通过当前的状态来判断是把回调加到回调列表里面还是直接执行fulfill或者reject方法。
this.then = function (onFulfilled, onRejected) {
var self = this;
return new Promise(function (resolve, reject) {
return self.done(function (result) {
if (typeof onFulfilled === 'function') {
try {
return resolve(onFulfilled(result));
} catch (ex) {
return reject(ex);
}
} else {
return resolve(result);
}
}, function (error) {
if (typeof onRejected === 'function') {
try {
return resolve(onRejected(error));
} catch (ex) {
return reject(ex);
}
} else {
return reject(error);
}
});
});
}
then方法很关键,也较难懂。这边写的有点多,感觉实现2写的好一点,把这些逻辑放在另外一个位置而不是在构建新promise的过程中。单纯从理解上来讲。
首先分析下每个参数的意思。
this.then = function (onFulfilled, onRejected)这里面的onFulfilled,onRejected是then方法给当前这个Promise注册的两个方法。
return new Promise(function (resolve, reject)这里的return new Promise就是为了新建一个Promise从而可以进行链式then方法的调用. then(fn1,fn2).then(fn3,fn4)=>var promise = then(fn1,fn2);
promise.then(fn3,fn4);resolve和reject则是这个新生成的promise的状态设置方法。
self.done(function (result),function(error));调用初始的promise的done方法,将匿名函数function(result)和匿名函数function(error)添加到原始promise的回调列表。
然后再来看看匿名函数function(result)应该怎么执行。
function (result) {
if (typeof onFulfilled === 'function') {
try {
return resolve(onFulfilled(result));
} catch (ex) {
return reject(ex);
}
} else {
return resolve(result);
}
}
如果then方法注册的是function,那么肯定是要用这个function去执行,onFulfilled(result)就是这个作用。
resolve是新产生的resolve的状态设定器。执行完onFulfilled(result),产生的结果假如是newresult再交给resolve去执行。新的promise的resolve方法就会将新的promise的状态设置成fulfilled,那么新promise的then方法就可以在注册完后续的方法后接着执行。resolve(newresult)就将onFulfilled(result)产生的结果
传递给了后续的then方法注册的function。
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;
}
getThen方法是为了查看这个结果是不是一个Promise或者说是含有then方法的Object.如果有then方法,就把then方法返回,否则就返回null
function resolve(result) {
try {
var then = getThen(result);
if (then) {
doResolve(then.bind(result), resolve, reject)
return
}
fulfill(result);
} catch (e) {
reject(e);
}
}
resolve这个方法可以处理参数是正常数值或者是Promise。根据Promise的使用说明,A promise resolve(Promise B),那么Promise A的状态会在Promise B的状态发生变化(变成fulfilled或者rejected)才会变化。首先用getThen来确定给定的参数是不是有then函数的Object,如果不是,那么就是单纯的将值赋给Promise A的内部变量value,后续回调函数就可以用这个value作为参数,这也是为什么resolve能把其参数传给通过then注册的回调函数。那么如果是有then函数的object呢,首先getThen返回了那个object的then函数。
然后then.bind(result)是让then函数的调用在拥有这个then函数的object里面执行,也就是resolve的参数result。然后doResolve实际上也就是执行了result这个promise的then方法。只不过注册的两个方法是当前这个
promise的resolve和reject方法。
所以实际上执行的是promiseB.then(resolve,reject);根据我们前面对then方法的分析可以知道。当promiseB的状态发生了改变,相关的回调函数会被执行,上面注册的是Promise A的resolve和reject方法作为promiseB的回调函数,那么Promise A的resolve/reject函数会在promiseB的状态改变后被执行,那么PromiseA的状态就发生了改变。同时PromiseB中产生的结果也会通过resolve这个函数传给Promise A.
这个其实看实现2的handle方法以及then如何调用handle方法会更容易理解一点。而且作者画了个很详细的图。
还忘了一点,就是为啥then方法前面有this。后来我觉得无所谓,然后把this去掉了,结果在调用的时候没法调用这个then函数。this.then应该是接口吧。虽然当时在W3Cschool上学习原型构造的时候很认真,但是还是忽略了习以为常的this。直到有的function有this,有的没有,才感觉有点奇怪,我自己写的时候怎么判断要不要加this啊。
大致就是这样。匿名函数的调用,传入的参数以及实际使用的参数,会引起很多干扰,说到底还是不太熟悉javascript的调用和特色吧。但是应该有更好的书写方式吧。所说的东西只是自以为是的理解,实在很难确信自己是对的。因为觉得是对的,所以就会朝那个方向去靠,有点像老师解答试卷的标准答案一样,即使标准答案是错的。网上还是充斥着很多不怎么准确的东西的,还是按照自己的意愿、想法去测试下。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。