实现原理
参考:
https://www.promisejs.org/implementing/
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise/then
promise是一个状态机,代表了异步操作的结果,一个promise就是以下三个状态之一:
- pending
- fulfilled
- rejected
当promise为成功或者拒绝之后,就不可再更改。
var PENDING = 0;
var FULFILLED = 1;
var REJECTED = 2;
function Promise() {
var state = PENDING;
var value = null;
var handlers = [];
}
实现完成或者拒绝这两个关键状态的转变
function fulfill(result) {
state = FULFILLED;
value = result;
}
function reject(error) {
state = REJECTED;
value = error;
}
}
这两个转变仅仅针对于返回值为一个平凡值(plain value),应对返回值是更复杂的情况就提出了高级一点的resolve
function resolve(result) {
try {
var then = getThen(result);
if (then) {
doResolve(then.bind(result), resolve, reject)
return
}
fulfill(result);
} catch (e) {
reject(e);
}
}
}
resolve中使用到了两个辅助函数getThen()和doResolve(),如下:
/**
* Check if a value is a Promise and, if it is,
* return the `then` method of that promise.
*
* @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;
}
/**
* Take a potentially misbehaving resolver function and make sure
* onFulfilled and onRejected are only called once.
*
* Makes no guarantees about asynchrony.
*
* @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)
}
}
doResolve()接受了三个参数,第一个为函数(在resolve中就是指的result.then,onFulfilled即成功时的操作在前文中为resolve,onRejected即拒绝时的操作在前文中为rejected),先初始为未完成状态( done = false),fn接收两个函数为参数,第一个参数为成功时的操作,第二个参数为拒绝时的操作,因为onFulfilled为resolve,也就是在这里resolve会被调用到直到then不存在,去完成fulfill操作。
到此为止,状态机部分已经完成了,但我们的终极目标是去实现 .then,在此之前,.done 更简单,所以先去实现它。
promise.done(onFulfilled, onRejected)的为了实现
- onFulfilled, onRejected只能调用其中一个
- 只能调用一次
- 在下一次回调之前不能被调用
- 无论在我们调用.call之前或者之后promise已经被解决了,都会被调用
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);
}
}
}
this.done = function (onFulfilled, onRejected) {
// ensure we are always asynchronous
setTimeout(function () {
handle({
onFulfilled: onFulfilled,
onRejected: onRejected
});
}, 0);
}
可看出在handle()部分实现了要么执行onFulfilled要么执行onRejected
.done实现之后,下面就是 .then 的实现,不同的是其中new了一个Promise
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);
}
});
});
}
/********************************************************/
this.then = function (onFulfilled, onRejected) {
var self = this;
return new Promise(function (resolve, reject) {
return self.done(function (result) { /*resolve*/ },
function (error) { /*reject*/ });
});
}
- 如果then中的回调函数返回一个值,那么then返回的Promise将会成为接受状态,并且将返回的值作为接受状态的回调函数的参数值
- 如果then中的回调函数没有返回值,那么then返回的Promise将会成为接受状态,并且该接受状态的回调函数的参数值为 undefined
- 如果then中的回调函数抛出一个错误,那么then返回的Promise将会成为拒绝状态,并且将抛出的错误作为拒绝状态的回调函数的参数值
- 如果then中的回调函数返回一个已经是接受状态的Promise,那么then返回的Promise也会成为接受状态,并且将那个Promise的接受状态的回调函数的参数值作为该被返回的Promise的接受状态回调函数的参数值
- 如果then中的回调函数返回一个已经是拒绝状态的Promise,那么then返回的Promise也会成为拒绝状态,并且将那个Promise的拒绝状态的回调函数的参数值作为该被返回的Promise的拒绝状态回调函数的参数值。
- 如果then中的回调函数返回一个未定状态(pending)的Promise,那么then返回Promise的状态也是未定的,并且它的终态与那个Promise的终态相同;同时,它变为终态时调用的回调函数参数与那个Promise变为终态时的回调函数的参数是相同的。