带你手写一个高级的Promise!!!
前言
Promise的A+规范
要手写一个Promise 我们要先去了解一下 Promise 的A+规范是什么。Promise 的 A+ 规范是一种关于 Promise 实现的标准,旨在确保不同 Promise 实现之间的行为一致性,从而提高了代码的可移植性和互操作性。A+ 规范定义了 Promise 对象的行为、方法和状态转换等方面的标准,确保了不同的 Promise 实现可以在相同的基础上工作。
A+规范包含了哪些
1. Promise 的状态
Promise 可以处于以下三种状态之一:
- Pending(进行中): 初始状态,表示异步操作正在进行中,尚未完成。
- Fulfilled(已成功): 表示异步操作已经成功完成。
- Rejected(已失败): 表示异步操作失败或出错。
状态只能从 Pending 转换到 Fulfilled 或者 Rejected,且状态一经改变就不可逆。
2. Promise 的 then 方法
Promise 对象必须提供一个 then()
方法来访问其最终的结果。then()
方法接受两个参数:onFulfilled 和 onRejected,分别表示在 Promise 成功和失败时执行的回调函数。
3. then 方法的链式调用
Promise 的 then()
方法必须返回一个新的 Promise 对象,并且允许链式调用。这意味着可以通过多次调用 then()
方法来对异步操作的结果进行链式处理。
4. 异步执行
Promise 的回调函数必须异步执行,即需要在当前脚本的所有同步任务执行完毕后执行,这样可以保证在回调函数执行时,Promise 的状态已经确定。
5. Promise 的错误处理
Promise 必须提供一个 .catch()
方法来捕获异步操作中的错误,并且 .catch()
方法返回一个新的 Promise 对象。
6. Promise 的状态改变
Promise 的状态一经改变就不可再次改变,且必须遵循状态转换的顺序:Pending -> Fulfilled 或 Pending -> Rejected。
7. Promise 的错误传递
Promise 的错误必须通过 .catch()
方法或者下一个 then()
方法的第二个参数来传递。
8. Promise 的解决值
Promise 的解决值是指成功状态的返回值,可以是任意 JavaScript 值(包括 undefined、null、基本类型、对象、函数等)。
9. Promise 的 thenable 对象
Promise 的 then 方法允许接受一个 thenable 对象(即具有 then()
方法的对象),并按照其返回的结果执行后续操作。
在了解了A+规范后我们就可以来更好更方便的实现一个Promise了。
实现过程
主要函数
function myPromise(fn) {
this.state = "pending";
this.value = null;
this.reason = null;
this.resCallback = [];
this.rejCallback = [];
const resolve = (value) => {
if (this.state === "pending") {
this.state = "fulfilld";
this.value = value;
this.resCallback.forEach((callback) => callback(this, value));
}
};
const reject = (reason) => {
if (this.state === "pending") {
this.state = "rejected";
this.reason = reason;
this.rejCallback.forEach((callback) => callback(this.reason));
}
};
try {
fn(resolve, reject);
} catch (error) {
reject(error);
}
-
在以上代码中,我们构建了一个自定义 Promise 类
myPromise
。它接受一个参数fn
,这个参数是一个执行器函数,它会立即执行,并且接收两个参数resolve
和reject
,分别用于将 Promise 状态设置为成功(fulfilled)或失败(rejected)。 -
myPromise
对象具有以下属性:state
: 表示 Promise 的状态,初始状态为"pending"
。value
: 表示 Promise 成功时的返回值。reason
: 表示 Promise 失败时的原因。resCallback
: 一个数组,用于存储成功状态时的回调函数。rejCallback
: 一个数组,用于存储失败状态时的回调函数。
-
resolve
函数用于将 Promise 状态设置为成功(fulfilled),并将成功的值保存在value
属性中。然后遍历onFulfilled
数组,依次执行其中的回调函数,并传入成功的值作为参数。 -
reject
函数用于将 Promise 状态设置为失败(rejected),并将失败的原因保存在reason
属性中。然后遍历onRejected
数组,依次执行其中的回调函数,并传入失败的原因作为参数。 -
在
myPromise
的构造函数中,通过try...catch
语句执行执行器函数fn
,并捕获可能的错误。
实现.then
myPromise.prototype.then = function (onFulfilled, onRejected) {
onFulfilled =
typeof onFulfilled === "Function" ? onFulfilled : (value) => value;
rejCallback =
typeof onRejected === "Function"
? onRejected
: (reason) => {
throw reason;
};
if (this.state === "pending") {
return new myPromise((resolve, reject) => {
this.resCallback.push((value) => {
setTimeout(() => {
try {
const result = onFulfilled(value);
resolve(result);
} catch (err) {
reject(err);
}
}, 0);
});
this.rejCallback.push((reason) => {
setTimeout(() => {
try {
const result = onRejected(reason);
resolve(result);
} catch (err) {
reject(err);
}
}, 0);
});
});
}
if (this.state === "fulfilled") {
return new myPromise((resolve, reject) => {
setTimeout(() => {
try {
const result = onFulfilled(this.value);
resolve(result);
} catch (err) {
reject(err);
}
}, 0);
});
}
if (this.state === "rejected") {
return new myPromise((resolve, reject) => {
setTimeout(() => {
try {
const result = onRejected(this.reason);
resolve(result);
} catch (err) {
reject(err);
}
});
});
}
};
-
在上篇文章中我们讲过,then方法它接收两个参数,
onFulfilled
和onRejected
,分别表示在 Promise 状态变为成功时执行的回调函数和在状态变为失败时执行的回调函数。 -
在
then
方法中,首先对传入的回调函数参数进行类型检查,如果传入的参数不是函数,则分别设置默认的回调函数。这里使用了箭头函数作为默认的回调函数,onFulfilled
的默认回调函数直接返回成功的值,onRejected
的默认回调函数直接抛出失败的原因。 -
接着根据 Promise 的状态进行不同的处理:
- 如果状态是
"pending"
,说明 Promise 尚未完成,此时需要将传入的回调函数添加到resCallback
或rejCallback
数组中,以便在状态变化后执行。 - 如果状态是
"fulfilled"
,则立即执行onFulfilled
回调函数,并将其结果作为新 Promise 的成功值,返回一个新的 Promise 对象。 - 如果状态是
"rejected"
,同样立即执行onRejected
回调函数,并将其结果作为新 Promise 的失败原因,返回一个新的 Promise 对象。
- 如果状态是
-
在执行回调函数时,使用
setTimeout
函数将回调函数的执行放入宏任务队列中,以确保在当前事件循环的末尾执行回调函数。这样做是为了保证 Promise 的异步执行行为,使得then
方法总是返回一个新的 Promise 对象。
catch和finally方法
myPromise.prototype.catch = function (onCatched) {
return this.then(null, onCatched);
};
myPromise.prototype.finally = function (onFinally) {
return this.then(
(value) => myPromise.resolve(onFinally()).then(() => value),
(reason) =>
myPromise.reject(onFinally()).catch(() => {
throw reason;
})
);
};
}
catch
方法它接收一个回调函数onCatched
,用于处理捕获到的错误。在实现中,catch
方法实际上是调用then
方法的特殊用法,将onCatched
函数作为onRejected
参数传入,而将onFulfilled
参数设置为null
,表示不处理成功的情况。finally
方法它接收一个回调函数onFinally
,用于执行最终的逻辑。在实现中,finally
方法也是通过调用then
方法来实现的。它通过在成功和失败的回调函数中分别执行onFinally
回调函数来实现。如果onFinally
函数返回的是一个 Promise 对象,会等待该 Promise 对象的状态变化后再继续执行后续逻辑;如果onFinally
函数抛出异常,则会将原来的失败原因重新抛出。
总结
以上就是本人对于如何手写实现一个Promise函数的理解,如有不足欢迎加以补充。
转载自:https://juejin.cn/post/7362023585518223400