Promise 是 JavaScript 异步编程的核心概念之一,我们将从基础到高级,一步步实现一个 MyPromise
类,以深入理解其内部机制。
1. 初步实现 resolve
和 reject
首先,我们来看一个 Promise 的基础用法:
javascript
const p1 = new Promise((resolve, reject) => {
resolve("success");
reject("fail");
});
const p2 = new Promise((resolve, reject) => {
reject("fail");
resolve("success");
});
console.log(p1);
console.log(p2);
以上例子执行的结果是
在这个例子中,我们可以观察到:
resolve
或reject
被调用后,Promise 状态(PromiseState
)就会锁定,后续的resolve
或reject
调用不会生效。resolve("success")
之后,reject("fail")
无效;同理,reject("fail")
之后,resolve("success")
也不会影响最终的状态。
基于这个行为,我们初步实现 MyPromise
:
javascript
class MyPromise {
constructor(executor) {
this.initValue();
try {
// 执行传进来的函数
executor(this.resolve, this.reject);
} catch (e) {
// 捕捉到错误直接执行reject
this.reject(e);
}
}
initValue() {
this.PromiseState = "pending";
this.PromiseResult = null;
}
resolve(value) {
if (this.PromiseState !== "pending") return;
this.PromiseState = "fulfilled";
this.PromiseResult = value;
}
reject(reason) {
if (this.PromiseState !== "pending") return;
this.PromiseState = "rejected";
this.PromiseResult = reason;
}
}
const mp1 = new MyPromise((resolve, reject) => {
resolve("success");
reject("fail");
});
console.log(mp1);
然而,执行后会报错:
原因分析 :
在 executor(this.resolve, this.reject);
这行代码中,resolve
和 reject
直接被调用,此时 this
指向 window
或 undefined
(在严格模式下)。
解决方案:
- 使用
bind
绑定this
,确保resolve
和reject
正确指向MyPromise
实例。
优化后:
javascript
class MyPromise {
constructor(executor) {
this.initValue();
this.initBind();
try {
// 执行传进来的函数
executor(this.resolve, this.reject);
} catch (e) {
// 捕捉到错误直接执行reject
this.reject(e);
}
}
initValue() {
this.PromiseState = "pending";
this.PromiseResult = null;
}
initBind() {
this.resolve = this.resolve.bind(this);
this.reject = this.reject.bind(this);
}
resolve(value) {
if (this.PromiseState !== "pending") return;
this.PromiseState = "fulfilled";
this.PromiseResult = value;
}
reject(reason) {
if (this.PromiseState !== "pending") return;
this.PromiseState = "rejected";
this.PromiseResult = reason;
}
}
2. 实现 then
方法
then
方法的作用是:
- 当 Promise 变为
fulfilled
时,执行onFulfilled
回调,并传入resolve
的值。 - 当 Promise 变为
rejected
时,执行onRejected
回调,并传入reject
的值。
示例代码:
javascript
const p3 = new Promise((resolve, reject) => {
resolve(1);
});
const p4 = new Promise((resolve, reject) => {
reject("失败");
});
p3.then(
(res) => console.log(res),
(error) => {
console.log(error);
}
);
p4.then(
(res) => console.log(res),
(error) => {
console.log(error);
}
);
这段代码的执行结果是
实现 then
方法:
javascript
then(onFulfilled, onRejected) {
onFulfilled = onFulfilled || ((value) => value);
onRejected =
onRejected ||
((reason) => {
throw reason;
});
if (this.PromiseState === "fulfilled") {
onFulfilled(this.PromiseResult);
} else if (this.PromiseState === "rejected") {
onRejected(this.PromiseResult);
}
}
3. 处理异步任务、值透传和链式调用
3.1 处理异步任务
如果 Promise
内部有异步任务,如 setTimeout
,当 then
执行时,PromiseState
仍然是 pending
。我们需要存储 then
的回调,待 resolve
或 reject
执行后再调用。
示例代码:
javascript
const p5 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1);
}, 1000);
});
p5.then((res) => res * 2).then((res) => console.log(res));
优化 MyPromise
:
javascript
class MyPromise {
constructor(executor) {
this.initValue();
this.initBind();
try {
// 执行传进来的函数
executor(this.resolve, this.reject);
} catch (e) {
// 捕捉到错误直接执行reject
this.reject(e);
}
}
initValue() {
this.PromiseState = "pending";
this.PromiseResult = null;
this.onFulfilledCallbacks = [];
this.onRejectedCallbacks = [];
}
initBind() {
this.resolve = this.resolve.bind(this);
this.reject = this.reject.bind(this);
}
resolve(value) {
if (this.PromiseState !== "pending") return;
this.PromiseState = "fulfilled";
this.PromiseResult = value;
while (this.onFulfilledCallbacks.length) {
this.onFulfilledCallbacks.shift()(this.PromiseResult);
}
}
reject(reason) {
if (this.PromiseState !== "pending") return;
this.PromiseState = "rejected";
this.PromiseResult = reason;
while (this.onRejectedCallbacks.length) {
this.onRejectedCallbacks.shift()(this.PromiseResult);
}
}
then(onFulfilled, onRejected) {
onFulfilled = onFulfilled || ((value) => value);
onRejected =
onRejected ||
((reason) => {
throw reason;
});
if (this.PromiseState === "fulfilled") {
onFulfilled(this.PromiseResult);
} else if (this.PromiseState === "rejected") {
onRejected(this.PromiseResult);
} else if (this.PromiseState === "pending") {
this.onFulfilledCallbacks.push(onFulfilled.bind(this));
this.onRejectedCallbacks.push(onRejected.bind(this));
}
}
}
3.2 处理值透传和链式调用
在 Promise 规范中,then
需要返回一个新的 Promise,这样才能支持链式调用。
javascript
class MyPromise {
constructor(executor) {
this.initValue();
this.initBind();
try {
// 执行传进来的函数
executor(this.resolve, this.reject);
} catch (e) {
// 捕捉到错误直接执行reject
this.reject(e);
}
}
initValue() {
this.PromiseState = "pending";
this.PromiseResult = null;
this.onFulfilledCallbacks = [];
this.onRejectedCallbacks = [];
}
initBind() {
this.resolve = this.resolve.bind(this);
this.reject = this.reject.bind(this);
}
resolve(value) {
if (this.PromiseState !== "pending") return;
this.PromiseState = "fulfilled";
this.PromiseResult = value;
while (this.onFulfilledCallbacks.length) {
this.onFulfilledCallbacks.shift()(this.PromiseResult);
}
}
reject(reason) {
if (this.PromiseState !== "pending") return;
this.PromiseState = "rejected";
this.PromiseResult = reason;
while (this.onRejectedCallbacks.length) {
this.onRejectedCallbacks.shift()(this.PromiseResult);
}
}
then(onFulfilled, onRejected) {
onFulfilled = onFulfilled || ((value) => value);
onRejected =
onRejected ||
((reason) => {
throw reason;
});
const thenPromise = new MyPromise((resolve, reject) => {
const resolvePromise = (callback) => {
try {
const result = callback(this.PromiseResult);
if (result instanceof MyPromise) {
result.then(resolve, reject);
} else {
resolve(result);
}
} catch (error) {
reject(error);
}
};
if (this.PromiseState === "fulfilled") {
resolvePromise(onFulfilled);
} else if (this.PromiseState === "rejected") {
resolvePromise(onRejected);
} else if (this.PromiseState === "pending") {
this.onFulfilledCallbacks.push(resolvePromise.bind(this, onFulfilled));
this.onRejectedCallbacks.push(resolvePromise.bind(this, onRejected));
}
});
return thenPromise;
}
}
4. 实现 all
, race
, any
, allSettled
这些方法是 Promise
的静态方法,涉及多个 Promise 的组合处理。
Promise.all
等待所有 Promise 完成,返回结果数组,如果有一个失败,则返回失败的结果。
Promise.race
返回第一个完成的 Promise 结果。
Promise.any
等待至少一个 Promise 成功,全部失败则返回 AggregateError
。
Promise.allSettled
等待所有 Promise 完成,返回包含 { status, value }
的结果数组。
完整代码如下:
javascript
class MyPromise {
constructor(executor) {
this.initValue();
this.initBind();
try {
// 执行传进来的函数
executor(this.resolve, this.reject);
} catch (e) {
// 捕捉到错误直接执行reject
this.reject(e);
}
}
initValue() {
this.promiseStatus = "pending";
this.promiseValue = null;
this.onFulfilledCallbacks = [];
this.onRejectedCallbacks = [];
}
initBind() {
this.resolve = this.resolve.bind(this);
this.reject = this.reject.bind(this);
}
resolve(value) {
if (this.promiseStatus !== "pending") return;
this.promiseStatus = "fulfilled";
this.promiseValue = value;
while (this.onFulfilledCallbacks.length) {
this.onFulfilledCallbacks.shift()(this.promiseValue);
}
}
reject(reason) {
if (this.promiseStatus !== "pending") return;
this.promiseStatus = "rejected";
this.promiseValue = reason;
while (this.onRejectedCallbacks.length) {
this.onRejectedCallbacks.shift()(this.promiseResult);
}
}
then(onFulfilled, onRejected) {
onFulfilled = onFulfilled || ((value) => value);
onRejected =
onRejected ||
((reason) => {
throw reason;
});
const thenPromise = new MyPromise((resolve, reject) => {
const resolvePromise = (callback) => {
try {
const result = callback(this.promiseResult);
if (result instanceof MyPromise) {
result.then(resolve, reject);
} else {
resolve(result);
}
} catch (error) {
reject(error);
}
};
if (this.promiseStatus === "fulfilled") {
resolvePromise(onFulfilled);
} else if (this.promiseStatus === "rejected") {
resolvePromise(onRejected);
} else if (this.promiseStatus === "pending") {
this.onFulfilledCallbacks.push(resolvePromise.bind(this, onFulfilled));
this.onRejectedCallbacks.push(resolvePromise.bind(this, onRejected));
}
});
return thenPromise;
}
static all(promises) {
let count = 0;
const result = [];
return new MyPromise((resolve, reject) => {
const addData = (res, index) => {
result[index] = res;
count++;
if (count === promises.length) resolve(result);
};
promises.forEach((promise, index) => {
if (promise instanceof MyPromise) {
promise.then(
(res) => {
addData(res, index);
},
(error) => {
reject(error);
}
);
} else {
addData(promise, index);
}
});
});
}
static race(promises) {
return new MyPromise((resolve, reject) => {
promises.forEach((promise) => {
if (promise instanceof MyPromise) {
promise.then(
(res) => {
resolve(res);
},
(error) => {
reject(error);
}
);
} else {
resolve(promise);
}
});
});
}
static any(promises) {
let count = 0;
return new MyPromise((resolve, reject) => {
const addData = () => {
count++;
if (count === promises.length)
reject(new AggregateError("All promises were rejected"));
};
promises.forEach((promise) => {
if (promise instanceof MyPromise) {
promise.then(
(res) => {
resolve(res);
},
(error) => {
addData();
}
);
} else {
resolve(promise);
}
});
});
}
static allSettled(promises) {
return new MyPromise((resolve, reject) => {
let count = 0;
const results = [];
const addData = (status, value, index) => {
results[index] = { status, value };
count++;
if (count === promises.length) {
resolve(results);
}
};
promises.forEach((promise, index) => {
if (promise instanceof MyPromise) {
promise.then(
(res) => {
addData("fulfilled", res, index);
},
(err) => {
addData("rejected", err, index);
}
);
} else {
addData("fulfilled", promise, index);
}
});
});
}
}
5. 总结
我们从最基础的 resolve/reject
开始,逐步实现 then
、异步处理、值透传、链式调用,并最终完成 all/race/any/allSettled
方法,完整实现了一个 Promise
类,深入理解了其运行机制。
📢 关于作者
嗨!我是头发秃头小宝贝,一名热爱技术分享的开发者,专注于Vue / 前端工程化 / 实战技巧 等领域。
如果这篇文章对你有所帮助,别忘了 点赞 👍 、收藏 ⭐ 和 关注 👏,你的支持是我持续创作的最大动力**!**