# promiseA+
promiseA+规范 (opens new window)
// https://promisesaplus.com/
// promise有三种状态
const PENDING = 'PENDING';
const RESOLVED = 'RESOLVED';
const REJECTED = 'REJECTED';
class Promise {
constructor(executor) {
// 当前Promise实例的状态,初始状态为PENDING
this.status = PENDING;
// 保存resolve时传入的值
this.value = undefined;
// 保存reject时传入的值
this.reason = undefined;
// 如果executor是异步的,将then接受的回调函数保存起来,异步结束的时候再执行
this.onResolvedCallBacks = [];
this.onRejectedCallBacks = [];
// resolve修改promise实例为成功状态
let resolve = value => {
// promise状态一旦改变就不能再修改了,所以只有在PENDING时resolve才有效
if (this.status === PENDING) {
this.status = RESOLVED;
this.value = value;
// 在then方法内订阅,保存回调函数;resolve时发布,执行回调函数
this.onResolvedCallBacks.forEach(cb => cb());
}
};
// reject修改promise实例为失败状态
let reject = reason => {
// promise状态一旦改变就不能再修改了,所以只有在PENDING时reject才有效
if (this.status === PENDING) {
this.status = REJECTED;
this.reason = reason;
// 在then方法内订阅,保存回调函数;reject时发布,执行回调函数
this.onRejectedCallBacks.forEach(cb => cb());
}
};
// executor内部代码可能会报错,所以用try catch
try {
executor(resolve, reject);
} catch (error) {
reject(error);
}
}
then(onResolved, onRejected) {
// onResolved和onRejected是可选参数,这里定义默认回调函数
// 比如 p = new Promise() p.then().then()
onResolved = typeof onResolved === 'function' ? onResolved : val => val;
onRejected =
typeof onRejected === 'function'
? onRejected
: err => {
throw err;
};
// 在then方法中new一个promise实例并返回,实现then的链式调用,即then返回的始终是一个promise实例
let nextPromise = new Promise((resolve, reject) => {
// 调用then方法时判断promise实例的状态
// 如果executor内已经resolve了
if (this.status === RESOLVED) {
// 2.2.4 onFulfilled or onRejected must not be called until the execution context stack contains only platform code.
// 由于new Promise在结束后才能赋值给变量nextPromise,因此使用setTimeout,保证processPromise能传入nextPromise
// 自己无法实现微任务,所以这里使用setTimeout
setTimeout(() => {
// onResolved是用户传入的回调,执行时可能会报错,使用try catch
try {
let data = onResolved(this.value);
// then的链式调用:将当前 onResolved回调 的结果传给nextPromise,processPromise做了一些判断和处理
processPromise(nextPromise, data, resolve, reject);
} catch (error) {
// onResolved执行出错,直接reject出去
reject(error);
}
}, 0);
}
// 如果executor内已经reject了
else if (this.status === REJECTED) {
setTimeout(() => {
try {
let data = onRejected(this.reason);
processPromise(nextPromise, data, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
}
// 如果executor是异步的,调用then时状态还是PENDING,则把回调函数先存起来,等异步结束后再执行回调函数
else if (this.status === PENDING) {
// 订阅回调函数
this.onResolvedCallBacks.push(() => {
setTimeout(() => {
try {
let data = onResolved(this.value);
processPromise(nextPromise, data, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
});
this.onRejectedCallBacks.push(() => {
setTimeout(() => {
try {
let data = onRejected(this.reason);
processPromise(nextPromise, data, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
});
}
});
return nextPromise;
}
finally(cb) {
return this.then(
data => {
return Promise.resolve(cb()).then(() => data);
},
err => {
return Promise.resolve(cb()).then(() => {
throw err;
});
}
);
}
catch(onRejected) {
return this.then(null, onRejected);
}
}
function processPromise(nextPromise, data, resolve, reject) {
// 根据A+规范
// case1、如果nextPromise和data是同一个值,则reject
// 比如:
// let p = new Promise((resolve, reject) => {
// resolve(100);
// });
// let p2 = p.then((data) => {
// return p2
// });
// 也就是说then最终会返回nextPromise,当onRejected或者onResolved也返回了nextPromise本身时,
// 就会造成链式循环引用,无法继续往下走
if (nextPromise === data) {
reject(new TypeError('Chaining cycle detected for promise #<Promise>]'));
}
// case2、如果data是一个object或者function
if ((typeof data === 'object' && data !== null) || typeof data === 'function') {
// 判断data是否具有then方法,如果有就可以认为data是一个promise
// case6:
// data是用户传入的promise,它可能是一个标准的promise,也可能没有严格遵守Promise的规范
// 未遵循规范时,当data里多次调用resolve或reject时,只执行第一个,忽略之后的
// 因此使用called作为标记来判断
let called = false;
try {
// 如果访问then属性时报错,则reject
// 比如当data的then属性被Object.defineProperties改写了getter方法抛出错误
let then = data.then;
// case4、如果then是一个function,则认为data是一个promise
if (typeof then === 'function') {
// 防止再次取then时可能发生报错,这里用第一次取的then的call方法
// data是一个promise,它可能会处于三种状态:
// 1)pending时,则必须等待,直到data的状态变为resolved(fulfilled)或者rejected。(这里是什么都不做)
// 2)resolved(fulfilled)时,调用data的then方法,在onResolved回调里将value再resolve出去
// 3)rejected时,调用data的then方法,在onRejected回调里将value再reject出去
then.call(
data,
y => {
if (called) return;
called = true;
// data里resolve出的y,可能仍然是一个promise,则递归处理,直到data是一个普通值,即走到case3
processPromise(nextPromise, y, resolve, reject);
},
r => {
if (called) return;
called = true;
reject(r);
}
);
} else {
// case5、data不具有then属性;data的then属性不是function,data是非promise对象;直接resolve
if (called) return;
called = true;
resolve(data);
}
} catch (error) {
if (called) return;
called = true;
reject(error);
}
} else {
// case3、data是常量
resolve(data);
}
}
Promise.resolve = function(value) {
if (value instanceof Promise) {
return value;
} else {
return new Promise((resolve, reject) => {
// value是Error实例时,还是resolve出去,此时传递的是Error实例对象本身,并不是执行出错
resolve(value);
});
}
};
Promise.reject = function(reason) {
return new Promise((resolve, reject) => {
reject(reason);
});
};
Promise.all = function(arr) {
return new Promise((resolve, reject) => {
let result = [];
let count = 0;
function _procressData(index, data) {
result[index] = data;
count++;
if (count === arr.length) {
resolve(result);
}
}
for (let i = 0; i < arr.length; i++) {
Promise.resolve(arr[i]).then(data => {
_procressData(i, data);
}, reject);
}
});
};
Promise.race = function(arr) {
return new Promise((resolve, reject) => {
for (let i = 0; i < arr.length; i++) {
Promise.resolve(arr[i]).then(
data => {
resolve(data);
},
err => {
reject(err);
}
);
}
});
};
// 用于跑 promiseA+ 的测试
Promise.defer = Promise.deferred = function() {
let dfd = {};
dfd.promise = new Promise((resolve, reject) => {
dfd.resolve = resolve;
dfd.reject = reject;
});
return dfd;
};
module.exports = Promise;