【javaScript】Promise 设计与实现
Promise 状态设置
Promise 一共由三种状态,pendding, fulfilled rejected。
const PROMISE_STATUS_PENDDING = "pendding";
const PROMISE_STATUS_FULFILLED = "fulfilled";
const PROMISE_STATUS_REJECTED = "rejected";
Promise 构造函数实现
我们知道 new Promise 时需要传入一个回调函数 executor, 这个函数会被立即执行,并且这个函数会有两个回调函数,resolve, reject。
- resolve 会将 Promise 状态变成 fulfilled 状态
- reject 会将 Promise 状态变成 rejected 状态
基本架构
const PROMISE_STATUS_PENDDING = "pendding";
const PROMISE_STATUS_FULFILLED = "fulfilled";
const PROMISE_STATUS_REJECTED = "rejected";
class ACPromise {
constructor(executor) {
// ACPromise 初始状态
this.status = PROMISE_STATUS_PENDDING;
const resolve = (res) => {};
const reject = (reason) => {};
executor(resolve, reject);
}
}
resolve 和 reject 实现
我们知道,resolve 时会调用 then 传入的第一个回调函数,reject 时会调用 then 传入的第二个回调函数。并且我们知道 then 传入的函数,是在主任务执行完成后,才执行,所以,回调函数的过程应该在微任务队列种。同时,我们需要 保存 resolve 和 reject 传入的参数,用户 promise 被多次调用then时,传入该值。
const PROMISE_STATUS_PENDDING = "pendding";
const PROMISE_STATUS_FULFILLED = "fulfilled";
const PROMISE_STATUS_REJECTED = "rejected";
class ACPromise {
constructor(executor) {
// ACPromise 初始状态
this.status = PROMISE_STATUS_PENDDING;
this.value = void 0;
this.reason = void 0;
this.onFulfilledFns = [];
this.onRejectedFns = [];
const resolve = (res) => {
// 保存 res
this.value = res;
// 将当前任务加入到微任务队列种
queueMicrotask(() => {
// 判断当前状态是否是Pendding状态
if (this.status !== PROMISE_STATUS_PENDDING) return;
// 修改Promise 状态
this.status = PROMISE_STATUS_FULFILLED;
// 执行then 方法传入的第一个回调函数
this.onFulfilledFns.forEach((fn) => fn(this.value));
});
};
const reject = (reason) => {
this.reason = reason;
// 加入到微任务队列
queueMicrotask(() => {
if (this.status !== PROMISE_STATUS_PENDDING) return;
// 修改 PROMISE 状态
this.status = PROMISE_STATUS_REJECTED;
// 执行 then 方法传入的第二个参数
this.onRejectedFns.forEach((fn) => fn(this.reason));
});
};
executor(resolve, reject);
}
}
Promise then 方法的实现
我们知道then 方法可以传入两个回调函数
- 第一个回调函数当promise状态变成 fulfilled 时,会被回调。
- 第二个回调函数当promise状态变成 rejected 时,会被回调。
并且我们知道 then 方法调用会返回一个非pendding 状态的Promise, 它的状态是由传入回调函数执行的返回值决定的,当回调函数抛出错误时调用reject,否则都是resolve.
then(onFulfilled, onRejected) {
const defaultOnFulfilled = (res) => res;
const defaultOnRejected = (err) => {
throw err;
};
// 用于防止链式调用时断层
// 就比如说当没有传递第二个参数时,此时抛出错误并不会返回一个Promise,这就会照成后面的捕获错误回调函数,捕获不到
if (!onFulfilled) onFulfilled = defaultOnFulfilled;
if (!onRejected) onRejected = defaultOnRejected;
return new ACPromise((resolve, reject) => {
// 判断当前Promise状态
if (this.status === PROMISE_STATUS_FULFILLED) {
try {
const result = onFulfilled(this.value);
resolve(result);
} catch (e) {
reject(e);
}
}
if (this.status === PROMISE_STATUS_REJECTED) {
try {
const result = onRejected(this.reason);
resolve(result);
} catch (e) {
reject(e);
}
}
if (this.status === PROMISE_STATUS_PENDDING) {
// 如果还是Pendding状态,表示当前主任务还在执行,将回调函数加入到队列种
this.onFulfilledFns.push((value) => {
try {
const result = onFulfilled(value);
resolve(result);
} catch (e) {
reject(e);
}
});
this.onRejectedFns.push((reason) => {
try {
const result = onRejected(reason);
resolve(result);
} catch (e) {
reject(e);
}
});
}
});
}
测试then 方法:
// 测试
const promise = new ACPromise((resolve, reject) => {
// resolve("成功哈哈哈哈");
reject("失败哈哈哈哈");
});
promise
.then(
(res) => {
console.log("res: ", res);
return "我是then方法第一个函数的返回值";
},
(err) => {
console.log("err: ", err);
return "我是then方法第二个函数的返回值";
}
)
.then(
(res) => {
console.log(res);
},
(err) => {
console.log(err);
}
);
err: 失败哈哈哈哈
我是then方法第二个函数的返回值
Promise 静态方法 resolve 实现
我们知道原生的Promise 静态方法 resolve 它接受一个参数,返回一个 fulfilled 状态的Promise
// 返回一个fulfilled状态的Promise,并且包含传入的值
static resolve(res) {
return new ACPromise((resolve, reject) => {
resolve(res);
});
}
测试 :
// 测试
const promise = ACPromise.resolve("测试静态方法resolve");
promise.then((res) => {
console.log(res); // 测试静态方法resolve
});
Promise 静态方法 reject 实现
我们知道 静态方法 reject也接受一个参数, 并返回也给 状态为 rejected 的 promise
// 返回一个rejected状态的Promise,并包含传入的值
static reject(reason) {
return new ACPromise((resolve, reject) => {
reject(reason);
});
}
测试:
// 测试
const promise = ACPromise.reject("测试静态方法reject");
promise.then(undefined, (err) => {
console.log(err); // 测试静态方法reject
});
Promise 静态方法 all 实现
我们知道 all 接受一组 promise, 并且等待所有 promise,状态全部变成 fulfilled 时,返回一个 状态为 fulfilled 的Promise, 并且附带这一组的结果。如果其中一个状态变成了 rejected ,那么就返回一个 状态为 rejected 的Promise, 并包含第一个 rejected 的错误信息
实现代码:
// all 方法实现
static all(promises) {
const result = [];
return new ACPromise((resolve, reject) => {
promises.forEach((promise) => {
promise.then(
(res) => {
result.push(res);
// 所有的promise都变成了 fulfilled 状态
if (result.length === promises.length) resolve(result);
},
(err) => {
// 一个变成 rejected 状态立马修改新的Promise状态为 rejected
reject(err);
}
);
});
});
}
测试所有都是 fulfilled
// 测试
const p1 = new ACPromise((resolve, reject) => {
resolve("Promise1");
});
const p2 = new ACPromise((resolve, reject) => {
resolve("Promise2");
});
const promise = ACPromise.all([p1, p2]);
promise.then((res) => {
console.log("全部变成fulfilled返回结果为: ", res);
});
// 输出: 全部变成fulfilled返回结果为: [ 'Promise1', 'Promise2' ]
测试存在一个rejected
// 测试
const p1 = new ACPromise((resolve, reject) => {
resolve("Promise1");
});
const p2 = new ACPromise((resolve, reject) => {
// resolve("Promise2");
reject("reject2");
});
const promise = ACPromise.all([p1, p2]);
promise.then(
(res) => {
console.log("全部变成fulfilled返回结果为: ", res);
},
(err) => {
console.log(err);
}
);
// 输出 reject2
Promise 静态方法 allSettled实现
我们知道 allSettled接受 一组 Promise, 并且等待所有Promise状态都变成 非Pendding状态后,才返回一个 fulfilled 状态的Promise, 并且该方法始终返回 fulfilled 状态的Promise。
实现代码:
static allSettled(promises) {
const result = [];
return new ACPromise((resolve, reject) => {
promises.forEach((promise) => {
promise.then(
(res) => {
result.push({ status: PROMISE_STATUS_PENDDING, value: res });
if (result.length === promises.length) resolve(result);
},
(err) => {
result.push({ status: PROMISE_STATUS_REJECTED, reason: err });
if (result.length === promises.length) resolve(result);
}
);
});
});
}
测试
// 测试
const p1 = new ACPromise((resolve, reject) => {
resolve("fulfilled1");
});
const p2 = new ACPromise((resolve, reject) => {
// resolve("Promise2");
reject("rejected2");
});
const promise = ACPromise.allSettled([p1, p2]);
promise.then((res) => {
console.log(res);
});
/*
输出
[
{ status: 'pendding', value: 'fulfilled1' },
{ status: 'rejected', reason: 'rejected2' }
]
*/
Promise 静态方法 race 实现
我们 知道 静态方法 race 接受一组Promise,并 会让第一个状态改变的Promise来决定返回Promise 的状态和回调函数的值。
static race(promises) {
return new ACPromise((resolve, reject) => {
promises.forEach((promise) => {
promise.then(
(res) => {
resolve(res);
},
(err) => {
reject(err);
}
);
});
});
}
测试:
// 测试
const p1 = new ACPromise((resolve, reject) => {
setTimeout(() => {
resolve("fulfilled1");
}, 1000);
});
const p2 = new ACPromise((resolve, reject) => {
// resolve("Promise2");
setTimeout(() => {
reject("rejected2");
}, 500);
});
const promise = ACPromise.race([p1, p2]);
promise.then(
(res) => {
console.log("res: ", res);
},
(err) => {
console.log("err: ", err);
}
);
Promise 静态方法 any 实现
静态方法 any 接受一组 Promise,并且只要这一组种 存在一个 fulfilled 状态的Promise就返回,fulfilled 状态的Promise, 否则直接返回一个 new AggregateError(reasons)。
static any(promises) {
const reasons = [];
return new ACPromise((resolve, reject) => {
promises.forEach((promise) => {
promise.then(
(res) => resolve(res),
(err) => {
reasons.push(err);
// 如果全部都是rejected则返回一个错误对象
if (reasons.length === promises.length)
reject(new AggregateError(reasons));
}
);
});
});
}
测试
const p1 = new ACPromise((resolve, reject) => {
setTimeout(() => {
reject("ssss");
}, 2000);
});
const p2 = new ACPromise((resolve, reject) => {
setTimeout(() => {
reject("reject");
}, 100);
// reject("ssss");
});
ACPromise.any([p1, p2]).then(
(res) => {
console.log(res);
},
(err) => {
console.log(err.errors);
}
);
// [ 'reject', 'ssss' ]
完整代码
const PROMISE_STATUS = {
PENDING: "pending",
FULFILLED: "fulfilled",
REJECTED: "rejected"
};
const tryCatchFuncResolveReject = (data, func, resolve, reject) => {
try {
const res = func(data);
resolve(res);
} catch(e) {
reject(e);
}
};
class WkPromise {
constructor(executor) {
this.status = PROMISE_STATUS.PENDING;
this.onFulfilledFuncs = [];
this.onRejectedFuncs = [];
this.value = void 0;
this.reason = void 0;
const resolve = (value) => {
this.value = value;
if (this.status !== PROMISE_STATUS.PENDING)
return;
this.status = PROMISE_STATUS.FULFILLED;
queueMicrotask(() => {
this.onFulfilledFuncs.forEach(fn => fn(value));
});
};
const reject = (reason) => {
this.reason = reason;
if (this.status !== PROMISE_STATUS.PENDING)
return;
this.status = PROMISE_STATUS.REJECTED;
queueMicrotask(() => {
this.onRejectedFuncs.forEach(fn => fn(reason));
});
};
try {
executor(resolve, reject);
} catch(e) {
reject(e);
}
}
then(onFulfilledFunc, onRejectedFunc) {
const defaultOnfulfilledFunc = (value) => value;
const defaultOnRejectedFunc = (reason) => { throw reason; };
onFulfilledFunc = onFulfilledFunc || defaultOnfulfilledFunc;
onRejectedFunc = onRejectedFunc || defaultOnRejectedFunc;
return new WkPromise((resolve, reject) => {
if (this.status === PROMISE_STATUS.PENDING) {
this.onFulfilledFuncs.push((value) => {
tryCatchFuncResolveReject(value, onFulfilledFunc, resolve, reject);
});
this.onRejectedFuncs.push((reason) => {
tryCatchFuncResolveReject(reason, onRejectedFunc, resolve, reject);
});
return;
}
// 当前Promise如果状态已经确定
if (this.status === PROMISE_STATUS.FULFILLED) {
queueMicrotask(() => {
tryCatchFuncResolveReject(this.value, onFulfilledFunc, resolve, reject);
});
}
if (this.status === PROMISE_STATUS.REJECTED) {
queueMicrotask(() => {
tryCatchFuncResolveReject(this.reason, onRejectedFunc, resolve, reject);
})
}
});
}
static resolve(value) {
return new WkPromise((resolve, reject) => resolve(value));
}
static reject(reason) {
return new WkPromise((resolve, reject) => reject(value));
}
static all(promises) {
const result = [];
return new WkPromise((resolve, reject) => {
promises.forEach((promise) => {
promise.then((res) => {
result.push(res);
if (result.length === promises.length)
resolve(result);
}, (err) => {
reject(err);
});
})
});
}
static allSettled(promises) {
const result = [];
return new WkPromise((resolve, reject) => {
promises.forEach(promise => {
promise.then((res) => {
result.push({
status: "fulfilled",
value: res
});
if (result.length === promises.length)
resolve(result);
}, (err) => {
result.push({
status: "rejected",
reason: err
});
if (result.length === promises.length)
resolve(result);
});
});
})
}
static race(promises) {
return new WkPromise((resolve, reject) => {
promises.forEach(promise => promise.then((res) => resolve(res), (err) => reject(err)));
});
}
static any(promises) {
const reasons = [];
return new WkPromise((resolve, reject) => {
promises.forEach(promise => {
promise.then(resolve, (err) => {
reasons.push(err);
if (reasons.length === promises.length)
reject(new Error(reasons));
})
})
})
}
}