手写 Promise,将静态方法和实例方法都进行了一遍实现。也可以实现链式调用。
/** * * 手写 promise * @class MaoPromise */ class MaoPromise { /** * 正在执行的状态 * * @static * @memberof MaoPromise */ static _PROMISE_STATUS_PENDING = "pending"; /** * 成功执行的状态 * * @static * @memberof MaoPromise */ static _PROMISE_STATUS_FULFILLED = "fulfilled"; /** * 失败执行的状态 * * @static * @memberof MaoPromise */ static _PROMISE_STATUS_REJECTED = "rejected"; /** * 默认的状态 执行中 * * @memberof MaoPromise */ _status = MaoPromise._PROMISE_STATUS_PENDING; /** * 成功执行时 传给 resolve 函数的参数 * * @memberof MaoPromise */ _value = undefined; /** * 失败执行时 传给 reject 函数的参数 * * @memberof MaoPromise */ _reason = undefined; /** * 成功执行的回调函数 * * @memberof MaoPromise */ _onFulfilledCallback = []; /** * 失败执行的回调函数 * * @memberof MaoPromise */ _onRejectedCallback = []; /** * Creates an instance of MaoPromise. * @param {Function} executor 执行器 * @memberof MaoPromise */ constructor(executor) { try { executor(this.resolve, this.reject); } catch (err) { this.reject(err); } } /** * 静态方法 resolve,返回一个执行成功回调的 promise 对象 * * @static * @param {*} value 执行成功回调 resolve 的参数 * @return {MaoPromise} * @memberof MaoPromise */ static resolve(value) { return new MaoPromise((resolve) => resolve(value)); } /** * 静态方法 reject 返回一个指向 reject 回调的 promise 对象 * * @static * @param {*} reason 执行 reject 回调的参数 * @return {MaoPromise} * @memberof MaoPromise */ static reject(reason) { return new MaoPromise((resolve, reject) => reject(reason)); } /** * * 静态方法 执行 promise 数组内的全部的 promise,全都执行完 且都是成功执行回调 * 则执行 resolve 回调,且参数为全部成功执行 promise 元素的回调函数 resolve 的参数的数组。一旦有一个 promise 元素执行了 reject 或者抛出异常,则终止执行且立刻执行 reject 回调 * @static * @param {Array} promises 是一个 promise 数组 * @return {*} * @memberof MaoPromise */ static all(promises) { return new MaoPromise((resolve, reject) => { const values = []; promises.forEach(promise => { promise.then(res => { values.push(res); if (values.length === promises?.length) resolve(values); }, err => reject(err)); }); }); } /** * * allSettled 返回一个在所有给定的 promise 都已经 fulfilled 或 rejected 后的 promise,并带有一个对象数组,每个对象表示对应的 promise 结果。 * @static * @param {Array} promises 是一个 promise 数组 * @return {*} * @memberof MaoPromise */ static allSettled(promises) { return new MaoPromise((resolve) => { const result = []; promises.forEach(promise => { promise.then(res => { result.push({ status: MaoPromise._PROMISE_STATUS_FULFILLED, value: res }); if (result.length === promises?.length) resolve(result); }, err => { result.push({ status: MaoPromise._PROMISE_STATUS_REJECTED, reason: err }); if (result.length === promises?.length) resolve(result); }); }) }); } /** * * promise 数组的元素 有一个 promise 拿到了结果,无论是成功还是失败,都直接结束 * @static * @param {Array} promises 是一个 promise 数组 * @memberof MaoPromise */ static race(promises) { return new MaoPromise((resolve, reject) => { promises.forEach(promise => { promise.then(resolve, reject); }); }); } /** * * 只要其中的一个 promise 成功,就返回那个已经成功的 promise 。 * 如果可迭代对象中没有一个 promise 成功(即所有的 promises 都失败/拒绝), * 就返回一个失败的 promise 和 AggregateError 类型的实例, * 它是 Error 的一个子类,用于把单一的错误集合在一起。 * 本质上,这个方法和 Promise.all()是相反的。 * @static * @param {Array} promises 是一个 promise 数组 * @return {*} * @memberof MaoPromise */ static any(promises) { return new MaoPromise((resolve, reject) => { const reasons = []; promises.forEach(promise => { promise.then(resolve, err => { reasons.push(err); if (reasons.length === promises?.length) reject(new AggregateError(reasons)); }); }); }); } /** * 成功时执行 * * @param {*} value * @memberof MaoPromise */ resolve = (value) => { if (this._status === MaoPromise._PROMISE_STATUS_PENDING) { // 延迟执行 queueMicrotask 函数 将回调函数的内容加入到微任务中执行 queueMicrotask(() => { if (this._status !== MaoPromise._PROMISE_STATUS_PENDING) return; this._value = value; this._status = MaoPromise._PROMISE_STATUS_FULFILLED; // 执行成功回调 this._onFulfilledCallback.forEach(callback => { callback(this._value); }); }); } } /** * 失败时执行 * * @param {*} reason * @memberof MaoPromise */ reject = (reason) => { if (this._status === MaoPromise._PROMISE_STATUS_PENDING) { queueMicrotask(() => { if (this._status !== MaoPromise._PROMISE_STATUS_PENDING) return; this._reason = reason; this._status = MaoPromise._PROMISE_STATUS_REJECTED; // 执行失败回调 this._onRejectedCallback.forEach(callback => { callback(this._reason); }); }); } } /** * then 方法 * * @param {*} onFulfilled 成功回调 * @param {*} onRejected 失败回调 * @memberof MaoPromise */ then(onFulfilled, onRejected) { // 如果 onRejected 函数没有传 想要在 catch 方法中传回调 // TODO 那么如果传入了 onRejected 回调,又使用 catch 进行捕获会如何? onRejected = onRejected ?? (err => { throw err }); // 如果第一个 then 的 resolve 函数有返回值,且链式调用过程后面出现的是 catch // 则成功回调函数是 undefined,也就是返回值不会被处理 // 所以我们需要在调用 catch 的时候,将上一个 resolve 的结果返回出去 // 如果不给 onFulfilled 赋值,则 catch 后面链式调用里面的回调函数都不会执行 onFulfilled = onFulfilled ?? (value => value); return new MaoPromise((resolve, reject) => { // TODO 执行 then 函数的时候,状态已经确定了,则直接执行成功回调函数 if (this._status === MaoPromise._PROMISE_STATUS_FULFILLED) { if (typeof onFulfilled === "function") { this._executorFunctionWithCatchError(onFulfilled, this._value, resolve, reject); } } else if (this._status === MaoPromise._PROMISE_STATUS_REJECTED) { if (typeof onRejected === "function") { this._executorFunctionWithCatchError(onRejected, this._reason, resolve, reject); } } else { // pending 状态 // TODO 副作用函数的返回值 作为 then 函数返回值 promise 的(resolve,reject)的参数 // 状态还没确定之前 搜集副作用 在状态改变之后 一起执行 if (typeof onFulfilled === "function") // 为了收集到副作用执行后的返回值 我们将副作用函数放到新的函数中 然后加入到副作用数组中 this._onFulfilledCallback.push(() => { this._executorFunctionWithCatchError(onFulfilled, this._value, resolve, reject); }); if (typeof onRejected === "function") this._onRejectedCallback.push(() => { this._executorFunctionWithCatchError(onRejected, this._reason, resolve, reject); }); } }); } /** * catch 方法的设计 巧妙的用了 then 方法, * 但是考虑到我们可能会在 catch 方法后面, * 链式的调用 finally 方法,所以需要将调用的 then 方法的返回值 继续返回 * * @param {*} onRejected 失败/异常处理回调 * @memberof MaoPromise */ catch(onRejected) { return this.then(undefined, onRejected); } /** * 最终执行 promise 的善后工作的代码 * * @param {*} onFinally 最终回调 * @memberof MaoPromise */ finally(onFinally) { // 还是借用 then 方法,不管成功还是失败/异常 都会执行最终回调 if (typeof onFinally === "function") this.then(() => { onFinally(); }, () => { onFinally(); }); } /** * 执行副作用函数 进行异常的捕获处理 * * @param {*} execFn 副作用函数 * @param {*} value 上一个回调函数(resolve,reject)执行时传入的参数 * @param {*} resolve 成功回调 * @param {*} reject 失败回调 * @memberof MaoPromise */ _executorFunctionWithCatchError(execFn, value, resolve, reject) { try { const res = execFn(value); resolve(res); } catch (err) { reject(err); } } } // MaoPromise.reject("err or").catch((err) => { // console.log(err); // }).finally(() => { // console.log("finally"); // }); const p1 = new MaoPromise((resolve, reject) => { setTimeout(() => { resolve(111); }, 1000); }); const p2 = new MaoPromise((resolve, reject) => { setTimeout(() => { reject(222); }, 2000); }); const p3 = new MaoPromise((resolve, reject) => { setTimeout(() => { resolve(333); }, 3000); }); MaoPromise.any([p2]).then((res) => { console.log(res); }).catch(err => { console.log(err.errors); })