什么是Promise
从本质上说,Promise 是一个用来处理异步操作的对象。它代表一个“未来才会知道结果”的操作 —— 成功某个值得到结果,失败某个理由出错
Promise的三种状态
Promise 有三种状态(状态机):
| 状态 | 含义 |
|---|---|
| pending(等待中) | 异步操作还没完成,也没失败,还未定论 |
| fulfilled(已成功) | 异步操作成功,得到了一个值 |
| rejected(已失败) | 异步操作失败,有一个错误原因 |
一旦从 pending 转到 fulfilled 或 rejected,状态就固定了,不会再变
Promise 的构造与用法
构造
创建一个 Promise 的基本形式是:
let p = new Promise((resolve, reject) => {
// 执行一些异步任务
if (成功) {
resolve(value);
} else {
reject(error);
}
});
这里的要点:
- executor 函数会被同步执行,也就是说在构造 Promise 的时候,executor 的代码会立刻跑(除非内部又异步,例如
setTimeout等) resolve(value):将 Promise 状态从 pending 变为 fulfilled,value 是最终值。reject(reason):将 Promise 状态变为 rejected,reason 通常是一个 Error 对象或其它说明失败的值。
Promise.prototype.then(onFulfilled, onRejected)
then方法返回的是一个新的Promise实例
.then(onFulfilled, onRejected?)
- 第一个参数是成功时处理函数
- 第二个是失败时处理函数(可选)
优点:
- 避免 回调 地狱(callback 嵌套太深)
- 逻辑更清晰,每一步处理一个任务
链式调用(Chaining)
.then() 会返回一个新的 Promise,所以可以链式地写多个 .then
此外,采用链式的then,可以指定一组按照指定次序调用的回调函数。因为后一个回调函数会等待上一个Promise实例对象的状态发生变化再被调用
doSomething()
.then(result => doSomethingElse(result))
.then(newResult => doThirdThing(newResult))
.catch(err => handleError(err));
Promise.prototype.catch(onRejected)
等同于 .then(null, onRejected),用来处理失败情况
Promise.prototype.finally(onFinally)
无论成功或失败,都会执行,用来做清理之类的工作
静态方法
resolve、reject、all、race、allSettled、any
Promise.resolve(value)
创建一个立即被fufilled的promise对象
thenable: 是一个对象(object/也可能是函数类的对象)具有
.then(...)方法的东西。simple as that.
Promise.reject(reason)
返回一个立刻 rejected 的 Promise
reject 是JavaScript Promise 中表示异步操作失败的函数,通过 new Promise((resolve, reject) => { ... reject(reason) ... }) 的形式在异步操作失败时调用,将Promise 的状态从 pending 变为 rejected。此外,Promise.reject(reason) 是一个静态方法,用于快速创建一个已拒绝的Promise 对象,其中 reason 是Promise 拒绝的原因
Promise.all(iterable)
并行等待全部完成;只要有一个失败就立刻失败
注意:
- 只要有一个 reject,整个
all直接 reject,看不到其它成功结果;需要“全量结果”请用allSettled - 返回值是按输入顺序排列的结果数组,与完成先后无关
Promise.race(iterable)
返回第一个完成的promise结果,无论是成功还是失败;常用于超时
时序细节:
- 空 iterable:返回的 Promise 会永远 pending。
- 包含已 settle 的值/非 Promise 值:会取到迭代中遇到的第一个(同一 tick 内按迭代顺序“不公平”地选择)
// 举例
const data = await Promise.race([
fetch('/api'),
new Promise((_, rej) => setTimeout(() => rej(new Error('Timeout')), 5000))
]);
// 先完成要么是 fetch,要么是 5 秒后超时
Promise.allSettled(iterable)
等待所有 Promise 完成(无论成功还是失败)
为每个 Promise 创建结果对象,包含 status 和对应的 value 或 reason:
-
成功项:
{ status: 'fulfilled', value } -
失败项:
{ status: 'rejected', reason }不会 reject。空 iterable 也直接 fulfilled(值为
[])
适用场景:你要收集全部结果做汇总/局部容错,而不是“一票否决”
Promise.any(iterable)
等到第一个fulfilled就成功,忽略之前所有的reject
若全部都 rejected,或传入空 iterable,则以 AggregateError 拒绝,并包含所有失败原因
和 race 的区别:race 只看谁先 settle(成功或失败都可能“赢”);any 只要第一个成功,失败不算“赢”
对比
| 组合器 | 何时 fulfilled | 何时 rejected | 典型用途 |
|---|---|---|---|
all | 全部成功 | 任何一个失败(立刻) | 需要所有结果且强一致 |
allSettled | 全部 settle 后一次性返回快照数组 | 不会 | 收集成功/失败明细、容错汇总 |
race | 第一个settle | 第一个settle(失败也算) | 竞速、超时(和计时器比跑) |
any | 第一个成功 | 全部失败→AggregateError | “谁先成功用谁” 的容错抓取 |
与 async / await 的关系
Promise 是底层机制,async / await 是语法糖,让异步的代码看起来像同步:
async function foo() {
try {
let result = await doSomething(); // 等待 doSomething 的 Promise resolve 或 reject
let more = await doSomethingElse(result);
return more;
} catch (e) {
// 捕获 reject
console.error(e);
throw e; // 如果希望继续传播错误
}
}
async函数返回一个 Promiseawait后面通常跟一个 Promise,await 会“暂停”当前 async 函数的执行,直到 Promise settle。- 错误处理可以像同步代码用
try/catch。比起纯.then().catch()链子更清晰
面试常考手撕题
手动实现 resolve/reject
class MyPromise {
constructor(executor){
// 初始状态为pending
this.state = "pending";
this.value = undefined; // 成功时的返回
this.reason = undefined; // 失败的原因
this.onFulfilledCallbacks = []; //存储成功的回调
this.onRejectedCallbacks = []; // 存储失败的回调
// 内部resove函数
const resolve = (value) => {
if(this.state === "pending"){
this.state = "fulfilled";
this.value = value;
this.onFulfilledCallbacks.forEach(callback => callback());
}
};
// 内部reject函数
const reject = (reason) => {
if(this.state === "pending"){
this.state = "rejected";
this.reason = reason;
this.onRejectedCallbacks.forEach(callback => callback());
}
};
try{
executor(resolve, reject);
}catch(error){
reject(error);
}
}
// then 方法:注册成功或失败的回调
then(onFulfilled, onRejected){
if(this.state === "fulfilled"){
onFulfilled(this.value);
}
if(this.state === "rejected"){
onRejected(this.reason);
}
// 如果状态还在 pending,就把回调存起来,等 resolve 或 reject 被调用时再触发
if(this.state === "pending"){
this.onFulfilledCallbacks.push(onFulfilled);
this.onRejectedCallbacks.push(onRejected);
}
}
}
// 应用
const p = new MyPromise((resolve, reject) => {
setTimeout(() => {
reject("出错啦!");
}, 1000);
});
p.then(
(value) => console.log("成功:", value),
(reason) => console.log("失败:", reason)
);
// 1秒后输出: 失败: 出错啦!
手动实现all
function myPromiseAll(promises){
return new Promise((resolve, reject) => {
// 边界情况:如果输入不是数组,直接reject
if(!Array.isArray(promises)){
reject(new TypeError('Promise.all 的参数必须是一个数组'));
return;
}
// 边界情况:如果数组为空,直接resolve空数组
if(promises.length === 0){
resolve([]);
return;
}
let result = [];
let count = 0;
promises.forEach((promise, index) => {
// 确保每个元素都是Promise
Promise.resolve(promise).then(res => {
result[index] = res; // 保持原始顺序
count++;
// 关键修复:在每次成功回调中检查是否所有Promise都完成了
if(count === promises.length){
resolve(result);
}
}).catch(reject); // 任何一个Promise失败都会导致整个all失败
});
});
}
myPromiseAll([Promise.resolve(1), Promise.resolve(2), Promise.resolve(3)]).then(res => {
console.log(res);
})
手动实现race
function myPromiseRace(promises) {
return new Promise((resolve, reject) => {
// 边界情况:如果输入不是数组,直接reject
if (!Array.isArray(promises)) {
reject(new TypeError('Promise.race 的参数必须是一个数组'));
return;
}
// 边界情况:如果数组为空,Promise永远不会resolve或reject
if (promises.length === 0) {
return; // 返回一个永远pending的Promise
}
// 遍历所有Promise,第一个完成的(成功或失败)就会触发resolve/reject
promises.forEach(promise => {
// 确保每个元素都是Promise
Promise.resolve(promise)
.then(resolve) // 第一个成功的Promise会触发resolve
.catch(reject); // 第一个失败的Promise会触发reject
});
});
}
手动实现any
function myPromiseAny(promises) {
return new Promise((resolve, reject) => {
// 边界情况:如果输入不是数组,直接reject
if (!Array.isArray(promises)) {
reject(new TypeError('Promise.any 的参数必须是一个数组'));
return;
}
// 边界情况:如果数组为空,直接reject
if (promises.length === 0) {
reject(new AggregateError([], 'All promises were rejected'));
return;
}
let rejectedCount = 0;
let errors = [];
promises.forEach((promise, index) => {
// 确保每个元素都是Promise
Promise.resolve(promise)
.then(resolve) // 第一个成功的Promise立即resolve
.catch(error => {
errors[index] = error;
rejectedCount++;
// 如果所有Promise都失败了,reject with AggregateError
if (rejectedCount === promises.length) {
reject(new AggregateError(errors, 'All promises were rejected'));
}
});
});
});
}
手动实现allsettled
function myPromiseAllSettled(promises) {
return new Promise((resolve, reject) => {
// 边界情况:如果输入不是数组,直接reject
if (!Array.isArray(promises)) {
reject(new TypeError('Promise.allSettled 的参数必须是一个数组'));
return;
}
// 边界情况:如果数组为空,直接resolve空数组
if (promises.length === 0) {
resolve([]);
return;
}
let result = [];
let count = 0;
promises.forEach((promise, index) => {
// 确保每个元素都是Promise
Promise.resolve(promise)
.then(res => {
// 成功的Promise
result[index] = {
status: 'fulfilled',
value: res
};
count++;
// 当所有Promise都完成时,resolve结果
if (count === promises.length) {
resolve(result);
}
})
.catch(error => {
// 失败的Promise
result[index] = {
status: 'rejected',
reason: error
};
count++;
// 当所有Promise都完成时,resolve结果
if (count === promises.length) {
resolve(result);
}
});
});
});
}
2万+

被折叠的 条评论
为什么被折叠?



