原文地址: https://www.jeremyjone.com/773/ ,转载请注明
写在前面
已经写了3篇前置内容了,主要是理解JS中的异步编程,异步的实现、以及异步的原理。今天内容较长,从最简单、最基本的内容入手,一点一点手撸一个简易的 Promise,巩固之前理解的异步原理,这才是我的目标。
手写 Promise
了解 Promise,从手动重写一个简易版的开始。
最简易的 Promise
最基本的 Promise 的样子是这样的:
new Promise((resolve, reject) => {
});
那么照猫画虎写一个:
class MyPromise {
constructor(executor) {
this.status = "pending";
this.value = null;
try {
executor(this.resolve.bind(this), this.reject.bind(this));
} catch (error) {
this.reject(error);
}
}
resolve(val) {
if (this.status === "pending") {
this.status = "fulfilled";
this.value = val;
}
}
reject(err) {
if (this.status === "pending") {
this.status = "rejected";
this.value = err;
}
}
}
这样就得到了一个最基本的样子,来试一下:
let p1 = new MyPromise((resolve, reject) => {
}); // 此时为 pending 状态
let p2 = new MyPromise((resolve, reject) => {
resolve();
}); // 此时为 fulfilled 状态
let p3 = new MyPromise((resolve, reject) => {
reject();
}); // 此时为 rejected 状态
好像没什么毛病了。接下来实现 then 的链式操作。
then 的实现
前文已经提到过,它应该也是一个方法,所以我们继续在 MyPromise 类中添加一个 then 方法:
// 继续添加代码,已有代码不再重复
class MyPromise {
constructor(executor) {
// 添加两个回调接收,用于 then 的异步回调
this.cbFulfilled = null;
this.cbRejected = null;
}
then(resolve, reject) {
// 先判断两个参数是否为函数,如果不是或者没有,给一个默认值
if (typeof resolve !== "function") {
resolve = () => {
};
}
if (typeof reject !== "function") {
reject = () => {
};
}
// 初始状态,异步情况下会是这个状态
if (this.status === "pending") {
this.cbFulfilled = resolve;
this.cbRjected = reject;
}
// 成功状态
if (this.status === "fulfilled") {
setTimeout(() => {
try {
resolve(this.value);
} catch (error) {
reject(error);
}
});
}
// 失败
if (this.status === "rejected") {
setTimeout(() => {
try {
reject(this.value);
} catch (error) {
reject(error);
}
});
}
}
// 修改之前的代码
resolve(val) {
if (this.status === "pending") {
this.status = "fulfilled";
this.value = val;
// 添加回调
setTimeout(() => {
this.cbFulfilled && this.cbFulfilled("timeout " + this.value);
});
}
}
reject(err) {
if (this.status === "pending") {
this.status = "rejected";
this.value = err;
// 添加回调
setTimeout(() => {
this.cbRejected && this.cbRejected("timeout " + this.value);
});
}
}
}
这里我们通过使用 setTimeout
来对执行顺序加以控制,使回调成为一个异步调用。测试一下:
let p1 = new MyPromise((resolve, reject) => {
console.log(1);
setTimeout(() => {
resolve("jeremyjone");
console.log(4);
});
console.log(2);
}).then(val => console.log(val));
console.log(3);
它的打印顺序:
1
2
3
4
jeremyjone
现在看上去已经和原生的效果差不多了。下一步我们让它成为链式的。
then 的链式实现
要实现链式操作,首先要明确:
- 它本身返回一个 Promise
- 它接收的状态并不会影响它新返回 Promise 的状态
既然是要一个 Promise,那么我们首先将 then
里面的方法包装在一个 Promise 中。然后稍微修改一下逻辑就可以实现链式操作了。
class MyPromise {
// ... 其他代码省略
then(resolve, reject) {
// 先判断两个参数是否为函数,如果不是或者没有,给一个默认值
if (typeof resolve !== "function") {
reso