手撸一个Promise:轻松掌握异步编程精髓
2023-09-27 13:39:45
揭秘 JavaScript Promise:从头撸起
理解宏任务与微任务
JavaScript 运行在单线程模型中,但是复杂的操作可能会阻塞线程。为了解决这个问题,JavaScript 引入了两种任务执行模式:
- 同步模式: 代码顺序执行,前一个任务完成后,后一个任务才能执行。
- 异步模式: 代码并发执行,任务可以同时执行,完成后将结果返回给主线程。
认识 Promise
Promise 是一种用于处理异步操作的 JavaScript API,它允许你指定异步操作完成后执行的任务,从而简化异步编程。
手撸一个 Promise
要深入理解 Promise,我们可以自己动手实现一个。
1. 构造函数
function Promise(executor) {
this.state = "pending"; // 初始状态
this.value = undefined; // 结果值
this.reason = undefined; // 失败原因
this.onFulfilledCallbacks = []; // 成功回调函数
this.onRejectedCallbacks = []; // 失败回调函数
const resolve = (value) => {
if (this.state !== "pending") return;
this.state = "fulfilled";
this.value = value;
this.onFulfilledCallbacks.forEach((callback) => callback(value));
};
const reject = (reason) => {
if (this.state !== "pending") return;
this.state = "rejected";
this.reason = reason;
this.onRejectedCallbacks.forEach((callback) => callback(reason));
};
executor(resolve, reject); // 立即执行
}
2. then 方法
Promise.prototype.then = function (onFulfilled, onRejected) {
return new Promise((resolve, reject) => {
if (this.state === "pending") {
this.onFulfilledCallbacks.push(() => {
try {
const result = onFulfilled(this.value);
resolve(result);
} catch (error) {
reject(error);
}
});
this.onRejectedCallbacks.push(() => {
try {
const result = onRejected(this.reason);
resolve(result);
} catch (error) {
reject(error);
}
});
} else if (this.state === "fulfilled") {
setTimeout(() => {
try {
const result = onFulfilled(this.value);
resolve(result);
} catch (error) {
reject(error);
}
}, 0);
} else if (this.state === "rejected") {
setTimeout(() => {
try {
const result = onRejected(this.reason);
resolve(result);
} catch (error) {
reject(error);
}
}, 0);
}
});
};
3. catch 方法
Promise.prototype.catch = function (onRejected) {
return this.then(null, onRejected);
};
4. finally 方法
Promise.prototype.finally = function (onFinally) {
return this.then(
(value) => {
onFinally();
return value;
},
(reason) => {
onFinally();
throw reason;
}
);
};
5. Promise.all 方法
Promise.all = function (promises) {
return new Promise((resolve, reject) => {
const results = [];
let count = 0;
promises.forEach((promise) => {
promise.then(
(value) => {
results[count] = value;
count++;
if (count === promises.length) {
resolve(results);
}
},
(reason) => {
reject(reason);
}
);
});
});
};
6. Promise.race 方法
Promise.race = function (promises) {
return new Promise((resolve, reject) => {
promises.forEach((promise) => {
promise.then(
(value) => {
resolve(value);
},
(reason) => {
reject(reason);
}
);
});
});
};
总结
通过手撸一个 Promise,我们深入了解了其内部工作原理。Promise 作为异步编程的利器,提供了更简洁优雅的解决方案。
常见问题解答
-
什么是宏任务和微任务?
宏任务:浏览器主线程上执行的任务,如 setTimeout、setInterval。微任务:在宏任务执行期间执行的任务,如 Promise 的 then 回调。 -
Promise 的状态有哪些?
pending:初始状态,等待操作完成。fulfilled:操作成功完成。rejected:操作失败。 -
如何使用 Promise.all?
将多个 Promise 放在数组中,传入 Promise.all(),当所有 Promise 都完成时,返回结果数组。 -
Promise.race 和 Promise.all 有什么区别?
Promise.race 返回第一个完成的 Promise,而 Promise.all 返回所有 Promise 完成后的数组。 -
为什么需要 finally 方法?
finally 方法用于在 Promise 完成后执行一些操作,无论 Promise 成功还是失败。