// MyPromise 的状态值,只有三种,定义成常量,方便复用,并且有代码提示方便编码
const PENDING = 'pending'; // 等待
const FULFILLED = 'fulfilled'; // 成功
const REJECTED = 'rejected'; // 失败
class MyPromise {
constructor(executor) { // 创建一个立即执行的执行器
try { // 对执行器进行错误捕获
executor(this.resolve, this.reject) // 立即执行
} catch (e) {
this.reject(e);
}
}
// 定义实例属性:每一个实例都有自己的实例状态和成功的值和失败的原因
status = PENDING; // 状态
value = undefined; // 成功之后的值
reason = undefined; // 失败后的原因
// 定义实例属性:存储状态确定后的回调,为了能同时存储多个回调所以用数组
successCallback = []; // 成功FULFILLED的回调
failCallback = []; // 失败REJECTED的回调
resolve = value => { // 用箭头函数来保证内部的this指向当前MyPromise的实例
// 如果状态不是PENDING就阻止程序向下执行(因为状态一旦确定就不会再变了)
if (this.status !== PENDING) return;
this.status = FULFILLED; // 将状态更改为成功
this.value = value; // 保存成功之后的值
// 判断成功回调是否存在 如果存在 调用
// this.successCallback && this.successCallback(this.value);
while (this.successCallback.length) this.successCallback.shift()()
}
reject = reason => {
// 如果状态不是PENDING就阻止程序向下执行(因为状态一旦确定就不会再变了)
if (this.status !== PENDING) return;
this.status = REJECTED; // 将状态更改为失败
this.reason = reason; // 保存失败后的原因
// 判断失败回调是否存在(也就是数组长度是否为0),如果存在就调用
// 循环数组中的值,不断用shift将数组元素弹出数组,并执行弹出的元素(元素就是存的回调函数)直到数组长度为0
while (this.failCallback.length) this.failCallback.shift()()
}
then(successCallback, failCallback) {
// 实现参数可选,如果没有successCallback就补一个,将上一个promise中的值向下传递
successCallback = successCallback ? successCallback : value => value;
// 实现参数可选,如果没有failCallback就补一个,将上一个promise中的值向下传递
failCallback = failCallback ? failCallback : reason => {
throw reason
};
// 因为then返回的是一个promise对象,所以需要先建立一个promise并返回
let promsie2 = new MyPromise((resolve, reject) => { // 这里面是立即执行的
// 对状态进行判断(包含同步异步的判断,前两个是同步的,最后一个else是异步)
if (this.status === FULFILLED) { // 同步 =>成功的状态FULFILLED
// 这里要注意,then返回的promise使用的是实例状态,默认值是PENDING
setTimeout(() => { // 这里如果不改成异步那么promise2是在new执行中获取的,显然获取不到
try {
let x = successCallback(this.value); // 拿到上一个then的返回值
// 调用这个内部的promise的resolve,就是把resolve的返回值传递给下一个then了
resolvePromise(promsie2, x, resolve, reject)
// 判断 x 的值是普通值还是promise对象,如果是普通值 直接调用resolve
// 如果是promise对象 查看promsie对象返回的结果
// 再根据promise对象返回的结果 决定调用resolve 还是调用reject
} catch (e) {
reject(e);
}
}, 0)
} else if (this.status === REJECTED) { // 同步 =>失败的状态REJECTED
setTimeout(() => {
try {
let x = failCallback(this.reason);
// 判断 x 的值是普通值还是promise对象,如果是普通值 直接调用resolve
// 如象果是promise对 查看promsie对象返回的结果
// 再根据promise对象返回的结果 决定调用resolve 还是调用reject
resolvePromise(promsie2, x, resolve, reject)
} catch (e) {
reject(e);
}
}, 0)
} else { // 异步等待的状态,等有状态变了再去执行对应的回调
// 所以需要将成功回调和失败回调存储起来,等状态确定了再调用
this.successCallback.push(() => { // 异步 =>将成功的回调存到数组中
setTimeout(() => {
try { // 使用try...catch来捕获错误
let x = successCallback(this.value);
// 判断 x 的值是普通值还是promise对象,如果是普通值 直接调用resolve
// 如果是promise对象 查看promsie对象返回的结果
// 再根据promise对象返回的结果 决定调用resolve 还是调用reject
resolvePromise(promsie2, x, resolve, reject)
} catch (e) {
reject(e);
}
}, 0)
});
this.failCallback.push(() => { // 异步 =>将失败的回调存到数组中
setTimeout(() => {
try { // 使用try...catch来捕获错误
let x = failCallback(this.reason);
// 判断 x 的值是普通值还是promise对象,如果是普通值 直接调用resolve
// 如果是promise对象 查看promsie对象返回的结果
// 再根据promise对象返回的结果 决定调用resolve 还是调用reject
resolvePromise(promsie2, x, resolve, reject)
} catch (e) {
reject(e);
}
}, 0)
});
}
});
return promsie2;
// 因为then返回的是一个promise对象,所以需要先建立一个promise并返回
}
finally(callback) { // 无论成功还是失败都要调用
return this.then(value => {
return MyPromise.resolve(callback()).then(() => value);
}, reason => {
return MyPromise.resolve(callback()).then(() => {
throw reason
})
})
}
catch (failCallback) { // 直接复用then和failCallback方法来捕获错误。
return this.then(undefined, failCallback)
}
// 静态方法:MyPromise.all
static all(array) {
let result = [];
let index = 0;
return new MyPromise((resolve, reject) => {
function addData(key, value) {
result[key] = value;
index++;
if (index === array.length) {
resolve(result); // 在都执行完了后才能调用result
}
}
for (let i = 0; i < array.length; i++) {
let current = array[i];
if (current instanceof MyPromise) {
// 判断,如果是promise 对象就执行promise对象
// 并且,如果有一个返回了reject,那么整个all都走reject
current.then(value => addData(i, value), reason => reject(reason))
} else {
// 普通值
addData(i, array[i]);
}
}
})
}
// 静态方法:MyPromise.resolve
static resolve(value) { // 首先判断是不是promise对象
if (value instanceof MyPromise) return value; // 如果是promise就直接返回
return new MyPromise(resolve => resolve(value)); // 如果不是就将其包装进promise
}
// 静态方法:MyPromise.reject
static reject(value) { // 首先判断是不是promise对象
if (value instanceof MyPromise) return value; // 如果是promise就直接返回
return new MyPromise((resolve,reject) => reject(value)); // 如果不是就将其包装进promise
}
// 静态方法:MyPromise.race
static race (value) {
let arr = Array.from(value) // 传递进来的参数可以是个类数组,后续操作将其转换为真数组
return new MyPromise(function(resolve, reject) {
for (let i = 0,len = arr.length; i < len; i++) { // 遍历数组,执行回调
MyPromise.resolve(arr[i]).then(value => {
resolve(value)
}, reason => {
return reject(reason)
})
}
})
}
}
// 把判断then返回值的方法抽离出来
function resolvePromise(promsie2, x, resolve, reject) {
if (promsie2 === x) { // 如果返回的是自身,那就抛出一个错误
return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
}
if (x instanceof MyPromise) { // 如果返回的是promise那就把回调值改成当前promise调用then
// promise 对象
// x.then(value => resolve(value), reason => reject(reason));
x.then(resolve, reject); // 由于上述具有之前封装的resolve和reject方法的格式,所以简化直接用
} else { // 如果返回的是普通值,那就直接调用resolve(x)
// 普通值
resolve(x);
}
}
module.exports = MyPromise;