function Promise(fn) {
// 判断 this一定得是object不然就会报错,这个方法一定得要new出来
if (typeof this !== 'object') {
throw new TypeError('Promises must be constructed via new');
}
// 判断fn 一定得是一个函数
if (typeof fn !== 'function') {
throw new TypeError('Promise constructor\'s argument is not a function');
}
this._deferredState = 0;
this._state = 0;
this._value = null;
this._deferreds = null;
if (fn === noop) return;
// 最终doResolve很关键
doResolve(fn, this);
}
/**
* Take a potentially misbehaving resolver function and make sure
* onFulfilled and onRejected are only called once.
*
* Makes no guarantees about asynchrony.
*/
//
// 确保`onFulfilled`和`onRejected`方法只调用一次
// 不保证异步
function doResolve(fn, promise) {
var done = false;
var res = tryCallTwo(fn, function (value) {
// 如果done 为true 则return
if (done) return;
done = true;
// 回调执行 resolve()
resolve(promise, value);
}, function (reason) {
// 如果done 为true 则return
if (done) return;
done = true;
reject(promise, reason);
});
// res为truCallTwo()的返回值
// 如果done没有完成 并且 res 是 `IS_ERROR`的情况下
// 也会执行reject(),同时让done完成
if (!done && res === IS_ERROR) {
done = true;
reject(promise, LAST_ERROR);
}
}
function safeThen(self, onFulfilled, onRejected) {
return new self.constructor(function (resolve, reject) {
var res = new Promise(noop);
res.then(resolve, reject);
handle(self, new Handler(onFulfilled, onRejected, res));
});
}
前言
then/promise
项目是基于Promises/A+
标准实现的Promise
库,从这个项目当中,我们来看Promise
的原理是什么,它是如何做到的,从而更加熟悉Promise
分析
从index.js当中知道,它是先引出了
./core.js
,随后各自执行了其他文件的代码,通过requeire
的方法。我们首先先想一下最基础的promise用法
Promise中的标准
标准中规定:
Pending
,在被resolve
或reject
时,状态变为Fulfilled
或Rejected
resolve
接收成功的数据,reject
接收失败或错误的数据Promise
对象必须有一个then
方法,且只接受两个可函数参数onFulfilled
、onRejected
index.js
我们先看
src/core.js
Promise
是一个构造方法,开始时,它进行了校验,确保了fn
是一个函数,随后对一些变量进行了初始化,最后执行了doResolve()
我们接着看
doResolve
这个方法。doResolve
最关键的是执行了tryCallTwo
方法,这个方法的第二,第三个参数都是回调,当执行回调后,done
为true,同时各自会执行resolve()
或者reject()
方法。最后当tryCallTwo
的返回值为IS_ERROR
时,也会执行reject()
方法。我们先来看一下
tryCallTwo
方法fn
实际就是Promise
初始化时的匿名函数(resolve, reject) => {}
,a
,b
则代表的是resolve()
和reject()
方法,当我们正常执行完promise
函数时,则执行的是resolve
则在doResolve中
,我们当时执行的第二个参数被回调,如果报错,reject()
被执行,则第二个参数被回调。最后捕获了异常,当发生了报错时,会return IS_ERROR
,非报错时会return undinfed
再回到刚才的
doResolve
方法,当执行了第二个参数的回调之后,会执行resolve
方法在没有链式调用
then
的情况下(也就是只要一个then
)的情况下,会将内部状态_state
设置成3
,将传入值赋给内部变量_value
最后会执行final()
方法,不然则会使用doResolve
来调用then
我们再来看下
reject
在
reject
当中我们的_state
变更为了2,同样最后finale
被调用。我们来看下
finale
函数在该方法当中根据不同的
_deferredState
,会执行不同的handle
方法。我们再来看
handle
方法这里比较关键的应该就是通过
deferredState
不同的状态,将deferred
放入deferreds
当中。另外当我们的_state
不为0
时,最终会执行handleResolved
。继续看
handleResolve()
方法在这个方法当中,会根据我们任务(_state)的不同状态,来执行
onFulfilled
或者onRejected
方法。当此方法调用时,也就是我们一个简单的Promise
的结束。回到刚才说的
Promise
构造方法结束的时候设置了
Promise
函数的一些变量随后在
Promise
的原型上设置了then
方法。在
then
这个方法中首先判断了它是否由Promise
构造的,如果不是,则返回并执行safeThen
,不然则执行Promise
构造一个res
对象,然后执行handle
方法,最后将promise
变量res
返回。handle
方法之前有提过,在这里,当初始化时_state
和_deferred
的转改都为0
,因此它会将defrred
保存到promise
当中。先看一下上面说的
safeThen
方法流程
需要有一个
Promise
的构造方法,这个构造方法最终会执行它的参数(resolve, reject) => {}
,声明的then
方法会通过handle()
方法将onFulfilled
和onRejected
方法保存起来。当在外部调用resolve
或者onRejected
时,最终也会执行handle
但是它,会最后根据状态来执行onFulfilled
或者onRejected
。从而到我们的then
回调中。Promise的扩展
done
对
done
的扩展在src/done.js
当中内部执行了
then()
finally
对
finally
的扩展在src/finally.js
当中在
Promise
的标准当中,本身是没有finally
方法的,但是在ES2018
的标准里有,finally
的实现如下Promise
的onFulfilled
和onRejected
不管回调的哪个,最终都会触发callback
回调。还要注意的一点是finally
的返回也是一个Promise
。es6-extensions.js
在
es6-extensions.js
文件当中包含了ES6的一些扩展。Promise.resolve
Promise.reject
Promise.all
Promise.all()
返回的也是一个Promise
函数。 内部有一个remaining
变量每当执行完一个promise
函数后就会减一,当所有promise
执行完,会执行自己的resolve
。Promise.race
遍历传入的
promise
数组,经过Promise.resolve(value)
的源码可以看到,如果value
是一个Promise
则户直接将这个value
返回,最后数组中的promise
哪个优先回调即执行。Promise.property.catch
catch
在标准当中也是没有,虽然我们用的比较多catch
的回调实际是then(null, onRejected)
的回调。广而告之
本文发布于薄荷前端周刊,欢迎Watch & Star ★,转载请注明出处。
欢迎讨论,点个赞再走吧 。◕‿◕。 ~