描述
MyPromise 实现了一个基本的 Promise 功能,包括状态管理、回调处理和静态方法。通过微任务处理,确保异步任务的正确执行顺序,适用于大多数现代浏览器环境。
知识点
- 使用
queueMicrotask、MutationObserver或setTimeout确保回调函数在微任务队列中执行。
/**
* 用于在微任务队列中执行回调函数。
* @param callback
*/
const runQueueMicrotask = (callback) => {
if (typeof queueMicrotask === "function") {
queueMicrotask(callback);
} else if (typeof MutationObserver === "function") {
const observer = new MutationObserver(callback);
const node = document.createTextNode("");
observer.observe(node, { characterData: true });
node.data = "";
} else {
setTimeout(callback);
}
};
一、实现构造函数
- 接受一个执行器函数
executor,该函数接受两个参数:resolve和reject。 resolve函数用于将 Promise 状态从PENDDING变为FULFILLED,并触发回调。reject函数用于将 Promise 状态从PENDDING变为REJECTED,并触发回调。
/**
*
// 状态常量
const PENDDING = "pendding";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";
class MyPromise {
// 状态
#state = PENDDING;
constructor(executor) {
// 成功回调 pendding => fulfilled
const resolve = (value) => {};
// 失败回调 pendding => rejected
const reject = (reason) => {};
try {
executor(resolve, reject);
} catch (e) {
reject(e);
}
}
}
二、 实现then方法
- 接受两个参数:
onFulfilled和onRejected,分别处理成功和失败的情况。 - 返回一个新的 Promise,确保链式调用。
- 根据当前状态,立即执行回调或存储回调等待状态改变。
/**
* @des 实现功能
*
* 1.状态不可变性
* pendding => fulfilled(实现)
* pendding => rejected(拒绝)
* 2.异步及多次调用
* 3.返回值是promise以及链式调用
* 4. 重复引用抛出异常 Chaining cycle detected for promise #<Promise>
*/
class MyPromise {
constructor(executor) {
// ···
}
// then 方法
then(onFulfilled, onRejected) {
// 规范要求,如果 onFulfilled 或 onRejected 不是函数,则忽略该参数,直接返回原值
onFulfilled = typeof onFulfilled === "function" ? onFulfilled : (x) => x;
onRejected =
typeof onRejected === "function"
? onRejected
: (x) => {
throw x;
};
// 返回一个新的 promise
const p2 = new MyPromise((resolve, reject) => {
const handlerCallback = (callback) => {
return () => {
runQueueMicrotask(() => {
try {
const x = callback(this.#result);
// 如果 x 与 p2 相等,则抛出异常
if (x === p2) {
throw new TypeError(
"Chaining cycle detected for promise #<Promise>"
);
}
if (x instanceof MyPromise) {
// 如果 x 是一个 promise,则将其状态一路向下传递,直到其状态为 fulfilled 或 rejected
x.then(
(res) => resolve(res),
(err) => reject(err)
);
} else {
// 如果 x 是一个对象,则将其直接返回
resolve(x);
}
} catch (e) {
// 捕获异常,如果**特别**的异常,则抛出异常,否则将异常传递给 reject
if (
e.message === "Chaining cycle detected for promise #<Promise>"
) {
throw e.message;
}
reject(e);
}
});
};
};
// 这里会有三种情况:
if (this.#state === FULFILLED) {
// 1. 当前 promise 状态为 fulfilled,则立即执行 onFulfilled 并返回一个新的 promise
handlerCallback(onFulfilled)();
} else if (this.#state === REJECTED) {
// 2. 当前 promise 状态为 rejected,则立即执行 onRejected 并返回一个新的 promise
handlerCallback(onRejected)();
} else {
// 3. 当前 promise 状态为 pendding,则将 onFulfilled 和 onRejected 存入 handlers 数组,等待状态改变时执行
this.#handlers.push({
onFulfilled: handlerCallback(onFulfilled),
onRejected: handlerCallback(onRejected),
});
}
});
return p2;
}
}
三、实例方法: catch/finally
- 接受一个
onRejected回调函数,等同于调用then(undefined, onRejected)。 - 接受一个
onFinally回调函数,无论 Promise 最终状态如何都会执行。
class MyPromise {
// catch方法
catch(onRejected) {
return this.then(undefined, onRejected);
}
// finally方法
finally(onFinally) {
return this.then(onFinally, onFinally);
}
}
四、静态方法: resolve/reject
- 返回一个已解决的 Promise。
- 返回一个已拒绝的 Promise。
class MyPromise {
// resolve静态方法
static resolve(value) {
if (value instanceof MyPromise) {
return value;
}
return new MyPromise((resolve) => {
resolve(value);
});
}
// reject静态方法
static reject(value) {
return new MyPromise((undefined, reject) => {
reject(value);
});
}
}
五、静态方法: race
- 接受一个 Promise 数组,返回一个 Promise,其状态由数组中最先改变状态的 Promise 决定。
class MyPromise {
// race静态方法
static race(promises) {
return new MyPromise((resolve, reject) => {
if (!Array.isArray(promises)) {
return reject(new TypeError("Argument is not iterable"));
}
promises.forEach((p) => {
MyPromise.resolve(p).then(
(res) => {
resolve(res);
},
(err) => {
reject(err);
}
);
});
});
}
}
六、静态方法: all
- 接受一个 Promise 数组,返回一个 Promise,当所有 Promise 都成功时才成功,否则失败。
class MyPromise {
// all静态方法
static all(promises) {
return new MyPromise((resolve, reject) => {
// 检查参数是否为数组
if (!Array.isArray(promises)) {
return reject(new TypeError("Argument is not iterable"));
}
// 处理空数组的情况
if (promises.length === 0) {
return resolve([]);
}
// 初始化结果数组和计数器
const results = [];
let count = 0;
promises.forEach((p, index) => {
MyPromise.resolve(p).then(
(res) => {
// 存储每个 Promise 的结果和跟踪已完成的 Promise 数量
results[index] = res;
if (++count === promises.length) {
resolve(results);
}
},
(err) => {
reject(err);
}
);
});
});
}
}
七、静态方法: allSettled
- 接受一个 Promise 数组,返回一个 Promise,当所有 Promise 都完成(无论成功或失败)时成功。
class MyPromise {
// allSettled静态方法
static allSettled(promises) {
return new MyPromise((resolve, reject) => {
// 检查参数是否为数组
if (!Array.isArray(promises)) {
return reject(new TypeError("Argument is not iterable"));
}
// 处理空数组的情况
if (promises.length === 0) {
return resolve([]);
}
// 初始化结果数组和计数器
const results = [];
let count = 0;
// handleResult 函数用于将每个 Promise 的结果存储到 results 数组中,并在所有 Promise 都处理完毕后调用 resolve。
const handleResult = (index, result) => {
results[index] = result;
if (++count === promises.length) {
resolve(results);
}
};
// 遍历 promises 数组,使用 MyPromise.resolve(p) 确保每个元素都是一个 Promise。然后,为每个 Promise 注册 then 回调,分别处理成功和失败的情况,并将结果传递给 handleResult 函数。
promises.forEach((p, index) => {
MyPromise.resolve(p).then(
(res) => handleResult(index, { status: FULFILLED, value: res }),
(err) => handleResult(index, { status: REJECTED, reason: err })
);
});
});
}
}
八、静态方法: any
- 接受一个 Promise 数组,返回一个 Promise,当数组中任意一个 Promise 成功时成功,所有都失败时失败。
class MyPromise {
// any静态方法
static any(promises) {
return new MyPromise((resolve, reject) => {
// 检查参数是否为数组
if (!Array.isArray(promises)) {
return reject(new TypeError("Argument is not iterable"));
}
// 处理空数组的情况
if (promises.length === 0) {
return reject(new AggregateError([], "All promises were rejected"));
}
const errors = new Array(promises.length);
let rejectedCount = 0;
promises.forEach((p, index) => {
MyPromise.resolve(p).then(resolve, (err) => {
errors[index] = err;
if (++rejectedCount === promises.length) {
reject(new AggregateError(errors, "All promises were rejected"));
}
});
});
});
}
}
完整代码
// 状态常量
const PENDDING = "pendding";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";
// 在微任务队列中执行回调函数
const runQueueMicrotask = (callback) => {
if (typeof queueMicrotask === "function") {
queueMicrotask(callback);
} else if (typeof MutationObserver === "function") {
const observer = new MutationObserver(callback);
const node = document.createTextNode("");
observer.observe(node, { characterData: true });
node.data = "";
} else {
setTimeout(callback);
}
};
class MyPromise {
// 状态
#state = PENDDING;
#result = undefined;
#handlers = [];
constructor(executor) {
// 成功回调 pendding => fulfilled
const resolve = (value) => {
if (this.#state === PENDDING) {
this.#state = FULFILLED;
this.#result = value;
this.#handlers.forEach(({ onFulfilled }) => {
onFulfilled(this.#result);
});
}
};
// 失败回调 pendding => rejected
const reject = (reason) => {
if (this.#state === PENDDING) {
this.#state = REJECTED;
this.#result = reason;
this.#handlers.forEach(({ onRejected }) => {
onRejected(this.#result);
});
}
};
try {
executor(resolve, reject);
} catch (e) {
reject(e);
}
}
// then 方法
then(onFulfilled, onRejected) {
// 规范要求,如果 onFulfilled 或 onRejected 不是函数,则忽略该参数,直接返回原值
onFulfilled = typeof onFulfilled === "function" ? onFulfilled : (x) => x;
onRejected =
typeof onRejected === "function"
? onRejected
: (x) => {
throw x;
};
// 返回一个新的 promise
const p2 = new MyPromise((resolve, reject) => {
const handlerCallback = (callback) => {
return () => {
runQueueMicrotask(() => {
try {
const x = callback(this.#result);
// 如果 x 与 p2 相等,则抛出异常
if (x === p2) {
throw new TypeError(
"Chaining cycle detected for promise #<Promise>"
);
}
if (x instanceof MyPromise) {
// 如果 x 是一个 promise,则将其状态一路向下传递,直到其状态为 fulfilled 或 rejected
x.then(
(res) => resolve(res),
(err) => reject(err)
);
} else {
// 如果 x 是一个对象,则将其直接返回
resolve(x);
}
} catch (e) {
// 捕获异常,如果**特别**的异常,则抛出异常,否则将异常传递给 reject
if (
e.message === "Chaining cycle detected for promise #<Promise>"
) {
throw e.message;
}
reject(e);
}
});
};
};
// 这里会有三种情况:
if (this.#state === FULFILLED) {
// 1. 当前 promise 状态为 fulfilled,则立即执行 onFulfilled 并返回一个新的 promise
handlerCallback(onFulfilled)();
} else if (this.#state === REJECTED) {
// 2. 当前 promise 状态为 rejected,则立即执行 onRejected 并返回一个新的 promise
handlerCallback(onRejected)();
} else {
// 3. 当前 promise 状态为 pendding,则将 onFulfilled 和 onRejected 存入 handlers 数组,等待状态改变时执行
this.#handlers.push({
onFulfilled: handlerCallback(onFulfilled),
onRejected: handlerCallback(onRejected),
});
}
});
return p2;
}
// catch方法
catch(onRejected) {
return this.then(undefined, onRejected);
}
// finally方法
finally(onFinally) {
return this.then(onFinally, onFinally);
}
// resolve静态方法
static resolve(value) {
if (value instanceof MyPromise) {
return value;
}
return new MyPromise((resolve) => {
resolve(value);
});
}
// reject静态方法
static reject(value) {
return new MyPromise((undefined, reject) => {
reject(value);
});
}
// race静态方法
static race(promises) {
return new MyPromise((resolve, reject) => {
if (!Array.isArray(promises)) {
return reject(new TypeError("Argument is not iterable"));
}
promises.forEach((p) => {
MyPromise.resolve(p).then(resolve, reject);
});
});
}
// all静态方法
static all(promises) {
return new MyPromise((resolve, reject) => {
// 检查参数是否为数组
if (!Array.isArray(promises)) {
return reject(new TypeError("Argument is not iterable"));
}
// 处理空数组的情况
if (promises.length === 0) {
return resolve([]);
}
// 初始化结果数组和计数器
const results = [];
let count = 0;
promises.forEach((p, index) => {
MyPromise.resolve(p).then(
(res) => {
// 存储每个 Promise 的结果和跟踪已完成的 Promise 数量
results[index] = res;
if (++count === promises.length) {
resolve(results);
}
},
(err) => {
reject(err);
}
);
});
});
}
// allSettled静态方法
static allSettled(promises) {
return new MyPromise((resolve, reject) => {
// 检查参数是否为数组
if (!Array.isArray(promises)) {
return reject(new TypeError("Argument is not iterable"));
}
// 处理空数组的情况
if (promises.length === 0) {
return resolve([]);
}
// 初始化结果数组和计数器
const results = [];
let count = 0;
// handleResult 函数用于将每个 Promise 的结果存储到 results 数组中,并在所有 Promise 都处理完毕后调用 resolve。
const handleResult = (index, result) => {
results[index] = result;
if (++count === promises.length) {
resolve(results);
}
};
// 遍历 promises 数组,使用 MyPromise.resolve(p) 确保每个元素都是一个 Promise。然后,为每个 Promise 注册 then 回调,分别处理成功和失败的情况,并将结果传递给 handleResult 函数。
promises.forEach((p, index) => {
MyPromise.resolve(p).then(
(res) => handleResult(index, { status: FULFILLED, value: res }),
(err) => handleResult(index, { status: REJECTED, reason: err })
);
});
});
}
// any静态方法
static any(promises) {
return new MyPromise((resolve, reject) => {
// 检查参数是否为数组
if (!Array.isArray(promises)) {
return reject(new TypeError("Argument is not iterable"));
}
// 处理空数组的情况
if (promises.length === 0) {
return reject(new AggregateError([], "All promises were rejected"));
}
const errors = new Array(promises.length);
let rejectedCount = 0;
promises.forEach((p, index) => {
MyPromise.resolve(p).then(resolve, (err) => {
errors[index] = err;
if (++rejectedCount === promises.length) {
reject(new AggregateError(errors, "All promises were rejected"));
}
});
});
});
}
}