Promise
是 JavaScript 中处理异步操作的核心工具之一。它提供了一种更优雅的方式来管理异步代码,避免了回调地狱(Callback Hell)。本文将分为两部分:第一部分介绍Promise
的使用与创建指南,第二部分手动实现一个简化版的Promise
,帮助你深入理解其工作原理。
Promise
是一个表示异步操作最终完成(或失败)及其结果值的对象。它有三种状态:
Pending(等待中):初始状态,既不是成功,也不是失败。
Fulfilled(已成功):操作成功完成。
Rejected(已失败):操作失败。
Promise
的核心功能是通过 then
、catch
和 finally
方法处理异步操作的结果。
你可以通过 new Promise()
构造函数来创建一个 Promise
对象。Promise
构造函数接受一个函数作为参数,这个函数有两个参数:resolve
和 reject
,它们都是函数。
resolve(value)
:当异步操作成功时调用,并将结果传递给 then
方法。
reject(error)
:当异步操作失败时调用,并将错误传递给 catch
方法。
const myPromise = new Promise((resolve, reject) => {
// 模拟异步操作
setTimeout(() => {
const success = true; // 假设这是一个异步操作的结果
if (success) {
resolve("操作成功!");
} else {
reject("操作失败!");
}
}, 1000);
});
创建 Promise
后,你可以使用 .then()
、.catch()
和 .finally()
方法来处理 Promise
的结果。
.then(onFulfilled, onRejected)
:当 Promise
被 resolve
时调用 onFulfilled
,当 Promise
被 reject
时调用 onRejected
。
.catch(onRejected)
:当 Promise
被 reject
时调用 onRejected
。
.finally(onFinally)
:无论 Promise
是 resolve
还是 reject
,都会调用 onFinally
。
myPromise
.then((result) => {
console.log(result); // 输出: "操作成功!"
})
.catch((error) => {
console.error(error); // 输出: "操作失败!"
})
.finally(() => {
console.log("操作完成。");
});
Promise
支持链式调用,你可以在一个 then
方法中返回一个新的 Promise
,然后在下一个 then
中处理它。
const promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(10);
}, 1000);
});
promise1
.then((value) => {
console.log(value); // 输出: 10
return value * 2;
})
.then((value) => {
console.log(value); // 输出: 20
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(value + 5);
}, 1000);
});
})
.then((value) => {
console.log(value); // 输出: 25
})
.catch((error) => {
console.error(error);
});
Promise
提供了一些静态方法,用于处理多个 Promise
:
Promise.resolve(value)
:返回一个以给定值解析的 Promise
对象。
Promise.reject(error)
:返回一个以给定原因拒绝的 Promise
对象。
Promise.all(iterable)
:当所有 Promise
都成功时返回一个包含所有结果的数组,如果有一个失败则立即返回失败的原因。
Promise.race(iterable)
:返回第一个完成(无论是成功还是失败)的 Promise
的结果。
const promise2 = Promise.resolve("立即解析");
const promise3 = Promise.reject("立即拒绝");
Promise.all([promise1, promise2])
.then((values) => {
console.log(values); // 输出: [10, "立即解析"]
})
.catch((error) => {
console.error(error);
});
Promise.race([promise1, promise2])
.then((value) => {
console.log(value); // 输出: "立即解析"
})
.catch((error) => {
console.error(error);
});
我们将实现一个简化版的 Promise
,支持以下功能:
基本的状态管理(pending
、fulfilled
、rejected
)。
then
方法:处理成功和失败的回调。
catch
方法:处理失败的回调。
静态方法:resolve
、reject
、all
和 race
。
Promise
的构造函数接受一个执行器函数(executor
),该函数有两个参数:resolve
和 reject
。
class MyPromise {
constructor(executor) {
this.status = 'pending'; // 初始状态
this.value = undefined; // 成功时的值
this.reason = undefined; // 失败时的原因
this.onFulfilledCallbacks = []; // 成功回调队列
this.onRejectedCallbacks = []; // 失败回调队列
const resolve = (value) => {
if (this.status === 'pending') {
this.status = 'fulfilled'; // 状态改为成功
this.value = value;
// 执行所有成功回调
this.onFulfilledCallbacks.forEach((fn) => fn());
}
};
const reject = (reason) => {
if (this.status === 'pending') {
this.status = 'rejected'; // 状态改为失败
this.reason = reason;
// 执行所有失败回调
this.onRejectedCallbacks.forEach((fn) => fn());
}
};
try {
// 执行传入的函数
executor(resolve, reject);
} catch (error) {
// 如果执行过程中出错,直接 reject
reject(error);
}
}
}
then
方法then
方法用于注册成功和失败的回调,并返回一个新的 Promise
,以支持链式调用。
then(onFulfilled, onRejected) {
// 如果 onFulfilled 不是函数,则提供一个默认函数
onFulfilled =
typeof onFulfilled === 'function' ? onFulfilled : (value) => value;
// 如果 onRejected 不是函数,则提供一个默认函数
onRejected =
typeof onRejected === 'function'
? onRejected
: (reason) => {
throw reason;
};
// 返回一个新的 Promise,支持链式调用
const promise2 = new MyPromise((resolve, reject) => {
if (this.status === 'fulfilled') {
// 如果当前状态是成功,异步执行 onFulfilled
setTimeout(() => {
try {
const x = onFulfilled(this.value);
// 处理返回值
this.resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
} else if (this.status === 'rejected') {
// 如果当前状态是失败,异步执行 onRejected
setTimeout(() => {
try {
const x = onRejected(this.reason);
// 处理返回值
this.resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
} else if (this.status === 'pending') {
// 如果当前状态是 pending,将回调放入队列
this.onFulfilledCallbacks.push(() => {
setTimeout(() => {
try {
const x = onFulfilled(this.value);
this.resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
});
this.onRejectedCallbacks.push(() => {
setTimeout(() => {
try {
const x = onRejected(this.reason);
this.resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
});
}
});
return promise2;
}
catch
方法catch
方法是 then
的语法糖,专门用于处理失败的回调。
catch(onRejected) {
return this.then(null, onRejected);
}
我们实现了以下静态方法:
MyPromise.resolve
:返回一个已解析的 Promise
。
MyPromise.reject
:返回一个已拒绝的 Promise
。
MyPromise.all
:等待所有 Promise
完成。
MyPromise.race
:返回第一个完成的 Promise
。
static resolve(value) {
return new MyPromise((resolve) => {
resolve(value);
});
}
static reject(reason) {
return new MyPromise((resolve, reject) => {
reject(reason);
});
}
static all(promises) {
return new MyPromise((resolve, reject) => {
const results = [];
let count = 0;
promises.forEach((promise, index) => {
MyPromise.resolve(promise).then(
(value) => {
results[index] = value;
count++;
if (count === promises.length) {
resolve(results);
}
},
(reason) => {
reject(reason);
}
);
});
});
}
static race(promises) {
return new MyPromise((resolve, reject) => {
promises.forEach((promise) => {
MyPromise.resolve(promise).then(
(value) => {
resolve(value);
},
(reason) => {
reject(reason);
}
);
});
});
}
const p1 = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve('成功');
}, 1000);
});
p1.then((value) => {
console.log(value); // 输出: "成功"
return '新的值';
})
.then((value) => {
console.log(value); // 输出: "新的值"
})
.catch((error) => {
console.error(error);
});
// 使用静态方法
MyPromise.all([p1, MyPromise.resolve('立即解析')]).then((values) => {
console.log(values); // 输出: ["成功", "立即解析"]
});
MyPromise.race([p1, MyPromise.resolve('立即解析')]).then((value) => {
console.log(value); // 输出: "立即解析"
});
通过本文,我们学习了 Promise
的基本用法,包括创建、使用、链式调用以及静态方法。同时,我们还手动实现了一个简化版的 Promise
,深入理解了 Promise
的核心机制,包括状态管理、回调队列、链式调用以及静态方法。虽然这个实现未完全符合 Promises/A+ 规范,但它足以帮助我们理解 Promise
的工作原理。
在实际开发中,建议使用原生 Promise
,因为它经过了严格测试和优化。但通过手动实现,我们可以更好地掌握异步编程的本质,写出更优雅、更易维护的代码。
希望这篇文章对你有所帮助!如果你有任何问题或建议,欢迎留言讨论。