萌新按照剖析 Promise 之基础篇学习实现了下promise,但是发现有一个很大的问题,那就是then在promise已改变状态下注册方法,该注册方法不会异步执行,变成了立即执行,请教下各位老哥,代码该如何修改(handle方法),还是说其他方法有问题,亦或是萌新我的理解有误。。。
代码如下:
const PENDING = 0;
const FULFILLED = 1;
const REJECTED = 2;
function SimplePromise(fn) {
let state = PENDING;
let value = null;
let deferreds = [];
this.then = function (onFulfilled, onRejected) {
return new SimplePromise (function (resolve, reject) {
// 当promise某一结果状态处理函数完成后,应将bridge promise状态改变,并向其传递结果值
handle({
onFulfilled: onFulfilled || null,
onRejected: onRejected || null,
resolve: resolve,
reject: reject
});
});
}
function handle(deferred) {
if (state === PENDING) {
deferreds.push(deferred);
return;
}
let cb = state === FULFILLED ? deferred.onFulfilled : deferred.onRejected;
// 当前promise一结果状态未注册相应处理函数,则将状态传递
if (cb === null) {
cb = state === FULFILLED ? deferred.resolve : deferred.reject;
cb(value);
return;
}
try {
let ret = cb(value);
deferred.resolve(ret);
} catch (e) {
deferred.reject(e);
}
}
function finale() {
setTimeout(function () {
deferreds.forEach(deferred => handle(deferred));
}, 0);
}
function resolve(newValue) {
// 用于处理方法返回的结果是promise
if (newValue && (typeof newValue === 'object' || typeof newValue === 'function')) {
let then = newValue.then;
if (typeof then === 'function') {
// bridge promise为了获取方法中返回的promise的结果值,向它注册异步操作后的处理函数
then.call(newValue, resolve, reject);
return;
}
}
state = FULFILLED;
value = newValue;
finale();
}
function reject(reason) {
state = REJECTED;
value = reson;
finale();
}
function doResolve(fn, resolve, reject) {
let done = false;
try {
fn(function (value) {
if (done) return;
done = true;
resolve(value);
}, function (reson) {
if (done) return;
done = true;
reject(reson);
})
} catch (e) {
if (done) return;
done = true;
reject(e);
}
}
doResolve(fn, resolve, reject);
}
比如在这种情况下会出现问题:
按规范不是应该先打印aaa吗?
function getUserId() {
return new SimplePromise(function (resolve) {
resolve(9876);
});
}
getUserId()
.then(function (mobile) {
console.log('do sth with', mobile);
return 'ccc';
})
.then(console.log);
console.log('aaa');
打印结果:
do sth with 9876
ccc
aaa