背景
刷掘金的时候无意中看到手写 promise 的文章,之前一直因为觉得太难没有尝试过,正好最近有时间,完整的读了下来,但是很多地方看不懂,于是也想着自己试试
参考文章
https://juejin.cn/post/7339042131467616296https://juejin.cn/post/7339042131467616296
https://juejin.cn/post/7346519210724786210https://juejin.cn/post/7346519210724786210
Promises/A+https://promisesaplus.com/
代码
/**
* 2.2.2.3 它不能被调用多次
* 2.2.3.3 它不能被调用多次
* 2.2.7.2 如果抛出了异常,以 reason 为返回值,执行 reject
*/
// 2.1 三种状态
const Status = {
PENDING: "pending",
FULFILLED: "fulfilled",
REJECTED: "rejected",
};
class XPromise {
/**
* 根据 promise 的使用,此处传入函数,参数为 resolve 和 reject
* @param executor 执行器
*/
constructor(executor) {
// 维护一个状态变量
this.status = Status.PENDING;
// 维护值和原因
this.value = undefined;
this.reason = undefined;
// 维护两个回调列表
this.onFulfilledCbLst = [];
this.onRejectedCbLst = [];
if (typeof executor !== "function") {
// 类型错误
throw new Error(`executor 应为函数`);
}
// pending -> fulfilled
const resolve = (value) => {
if (this.status === Status.PENDING) {
this.status = Status.FULFILLED;
this.value = value;
// 执行回调
this.onFulfilledCbLst.forEach((fn) => fn(value));
}
};
// pending -> rejected
const reject = (reason) => {
if (this.status === Status.PENDING) {
this.status = Status.REJECTED;
this.reason = reason;
// 执行回调
this.onRejectedCbLst.forEach((fn) => fn(reason));
}
};
executor(resolve, reject);
}
/**
* 2.2 then 方法,用于访问其当前或最终的值或原因
* @param onFulfilled Function 可选
* @param onRejected Function 可选
*/
then(onFulfilled, onRejected) {
const that = this;
// 2.2.7 then 返回一个 promise
let promise2 = new XPromise((resolve, reject) => {
// 2.2.2.1 在满足之后调用,以 promise2 value 作为第一个参数
function onFulfilledCb(value) {
/**
* 2.2.4 onFulfilled, onRejected 在执行上下文堆栈仅包含平台代码之前,不得调用
* 根据 gpt 回答,要在微任务中调用,所以先加入队列
*/
queueMicrotask(() => {
try {
const x = onFulfilled(value);
that.promiseResolve(promise2, x, resolve, reject);
} catch (error) {
// 2.2.7.2 如果 onFulfilled/onRejected 抛出异常,以 error 为理由拒绝
reject(error);
}
});
}
// 2.2.3.1 在被拒绝之后调用,以 promise2 reason 作为第一个参数
function onRejectedCb(reason) {
queueMicrotask(() => {
try {
const x = onRejected(reason);
that.promiseResolve(promise2, x, resolve, reject);
} catch (error) {
// 2.2.7.2 如果 onFulfilled/onRejected 抛出异常,以 error 为理由拒绝
reject(error);
}
});
}
// 2.2.2.2 onFulfilled 在实现之前不得调用
if (this.status === Status.FULFILLED) {
// 2.2.1.1 如果 onFulfilled 不是函数,忽略
if (typeof onFulfilled === "function") {
// 2.2.2.1 在满足之后调用,以 promise2 value 作为第一个参数
onFulfilledCb(this.value);
} else {
// 2.2.7.3 如果 onFulfilled 不是函数,且 promise1 状态是 FULFILLED
// promise2 以 promise1 相同的值变为已解决
resolve(this.value);
}
} else if (this.status === Status.REJECTED) {
// 2.2.3.2 onRejected 在被拒绝之前不得调用
// 2.2.1.2 如果 onRejected 不是函数,忽略
if (typeof onRejected === "function") {
// 2.2.3.1 在被拒绝之后调用,以 promise2 reason 作为第一个参数
onRejectedCb(this.reason);
} else {
// 2.2.7.4 如果 onRejected 不是函数,且 promise1 状态是 REJECTED
// promise2 以 promise1 相同的reason变为已拒绝
reject(this.reason);
}
} else {
if (typeof onFulfilled === "function") {
// 2.2.6.1 如果满足,onFulfilled 相应回调按对 then 发起调用的顺序执行
this.onFulfilledCbLst.push((value) => {
onFulfilledCb(value);
});
} else {
// 2.2.7.3 如果 onFulfilled 不是函数,且 promise1 状态是 FULFILLED
// promise2 以 promise1 相同的值变为已解决
this.onFulfilledCbLst.push((value) => {
resolve(value);
});
}
if (typeof onRejected === "function") {
// 2.2.6.2 如果拒绝,onRejected 相应回调按对 then 发起调用的顺序执行
this.onRejectedCbLst.push((reason) => {
onRejectedCb(reason);
});
} else {
// 2.2.7.4 如果 onRejected 不是函数,且 promise1 状态是 REJECTED
// promise2 以 promise1 相同的reason变为已拒绝
this.onRejectedCbLst.push((reason) => {
reject(reason);
});
}
}
});
return promise2;
}
/**
* 判断数据是否为纯 object【数组、null 会返回 false】
* @param obj 要判断的数据
*/
isObject(obj) {
return Object.prototype.toString.call(obj) === "[object Object]";
}
/**
* 解析过程,根据 promise a+ 步骤翻译
* 2.2.7.1 如果返回一个 value,运行 promise 内部的 resolve 解析函数
* 2.3 promise 解析过程是一个抽象操作,将 promise 和一个值作为输入
* promise2 指的是调用 then 方法返回的 promise
* x 指的是 then 方法的回调函数调用后得到的数据
* resolve 和 reject 是 promise2 构造函数中的参数
*/
promiseResolve(promise2, x, resolve, reject) {
// console.log("promise2", promise2, "x", x);
// 2.3.1 如果 x 和 promise2 引用同一个对象,以 typeError 作为理由拒绝
if (x == promise2) {
reject(new TypeError(`promise2 和 x 引用了同一对象`));
} else if (x instanceof XPromise) {
// 2.3.2 如果 x 是一个 promise
if (x.status === Status.PENDING) {
// 2.3.2.1 如果 x 处于待处理状态,promise 保持待处理状态,直到 x 已解决或已拒绝
// promise2 要在回调函数得到的 promise 状态变更后再变更状态
x.onFulfilledCbLst.push((value) => {
// resolve(value);
this.promiseResolve(promise2, value, resolve, reject);
});
x.onRejectedCbLst.push((reason) => {
reject(reason);
});
} else if (x.status === Status.FULFILLED) {
// 2.3.2.2 如果 x 已解决,promise 变更为已解决,值与 x 一致
// resolve(x.value);
this.promiseResolve(promise2, x.value, resolve, reject);
} else {
// 2.3.2.3 如果 x 已拒绝,promise 变更为已拒绝,reason 与 x 一致
reject(x.reason);
}
} else if (typeof x === "function" || this.isObject(x)) {
// 2.3.3 如果是个对象/函数
// 2.3.3.1 let then be x.then
try {
const then = x.then;
let called = false;
if (typeof then === "function") {
try {
// 2.3.3.3.3 如果同时调用或多次调用,第一个调用优先,忽略后续
if (!called) {
/**
* 2.3.3.3 如果 then 是个函数,call it with x as this,参数 resolvePromise rejectPromise
* 其中
* 2.3.3.3.1 如果 调用 resolvePromise,并赋值 y,执行 resolve(promise2, y)
* 2.3.3.3.2 如果 调用 rejectPromise,并附原因 r,promise2 变更为拒绝,r 为reason
* 说明:resolvePromise rejectPromise 对应 onFulfilled onRejected
*/
then.call(
x,
(y) => {
if (!called) {
// 重新执行
// 根据测试用例可以看到,y 可能是个异步 promise
this.promiseResolve(promise2, y, resolve, reject);
called = true;
}
},
(error) => {
if (!called) {
// 2.3.3.3.3 如果同时调用或多次调用,第一个调用优先,忽略后续
reject(error);
called = true;
}
}
);
}
} catch (error) {
// 2.3.3.3.4 如果调用 then 函数,报错
// 2.3.3.3.4.1 如果 resolvePromise/rejectPromise 已被调用,忽略
if (!called) {
called = true;
// 2.3.3.3.4.2 否则,promise2 变更为已拒绝,error 为 reason
reject(error);
}
}
} else {
// 2.3.3.4 如果 then 不是函数,promise2 变更为 FULFILLED value 取 x
resolve(x);
}
} catch (error) {
// 2.3.3.2 如果检索 x.then 导致异常,则 promise2 以 error 为理由拒绝
reject(error);
}
} else {
// 2.3.4 如果 x 不是函数或对象,promise2 变更为 FULFILLED value 取 x
resolve(x);
}
}
}
正文
https://www.yuque.com/tangxiaoxi-dfdne/aczo22/dghr8d1o4fk2evdb?singleDoc# 《手写 promise》