Promise 对象
在 JavaScript 中,Promise 用来表示一个异步操作的最终结果。
按照 MDN 的定义,Promise 表示“一个异步操作最终会完成还是失败,以及它对应的结果值”。你可以把它理解成:先拿到一个“未来结果的占位对象”,等异步任务结束后,再统一处理成功值或失败原因。
为什么要用 Promise
传统异步代码通常依赖回调函数。随着逻辑变复杂,回调会一层套一层,代码容易出现下面这些问题:
- 嵌套过深,可读性差
- 错误处理分散,不容易统一管理
- 多个异步步骤串联时,代码维护成本高
Note
- 支持链式调用,能明显缓解“回调地狱”
- 成功和失败的处理方式更统一
- 更容易组合多个异步任务
Promise 如何封装异步
最常见的写法是通过 new Promise(...) 创建一个 Promise 对象:
new Promise(executor)会立即创建一个 Promiseexecutor是执行器函数,它会同步执行executor接收两个参数:resolve和reject- 调用
resolve(value)表示操作成功 - 调用
reject(reason)表示操作失败

通常我们会在异步任务完成后调用 resolve 或 reject,再通过 then、catch、finally 注册后续处理逻辑。
下面是一个简单的抽奖示例。这里使用 setTimeout 来模拟异步操作;它不会阻塞主线程,只是 1 秒后再执行回调。
function getRandomNumber(min, max) {
return Math.ceil(Math.random() * (max - min + 1)) + min - 1;
}
const btn = document.querySelector("button");
btn.addEventListener("click", function () {
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
const num = getRandomNumber(1, 100);
if (num <= 30) {
resolve(num);
} else {
reject(num);
}
}, 1000);
});
promise.then(
(num) => {
console.log(`中奖了,号码是:${num}`);
},
(num) => {
console.log(`没中奖,再试一次:${num}`);
}
);
});
执行顺序
有一个很容易混淆的点:
Promise的执行器executor是同步执行的then、catch、finally注册的回调不会立刻执行- 这些回调会在当前同步代码执行结束后再执行
示例:
const promise = new Promise((resolve) => {
console.log("Promise");
resolve();
});
promise.then(() => {
console.log("resolved");
});
console.log("Hi!");
输出顺序:
原因是:^^执行器先同步运行,而 then 的回调会等当前调用栈清空后再执行.^^
Promise 的状态与结果
三种状态
Promise 只有三种状态:
pending:等待中fulfilled:已成功rejected:已失败
状态变化只有两种:
pending -> fulfilledpending -> rejected
并且一旦状态确定,就不会再改变。
结果值
除了状态,Promise 还会保存本次异步操作的结果:
- 成功时保存
value - 失败时保存
reason
后续的回调函数拿到的,就是这个结果值。
Note
有些资料会把 fulfilled 写成 resolved,但严格来说,resolved 不是 Promise 的正式状态名。
- 状态名只有:
pending、fulfilled、rejected settled表示“已经落定”,也就是fulfilled或rejectedresolved更准确地说是“已经被处理/跟随某个结果”,它不一定等于fulfilled
例如,一个 Promise 可以“resolved 到另一个 Promise”,但它自己此时仍然可能暂时处于 pending。
const inner = new Promise((resolve) => {
setTimeout(() => resolve("ok"), 1000);
});
const outer = Promise.resolve(inner);
outer.then((value) => {
console.log(value);
});
上面的 outer 会跟随 inner 的最终状态;在 inner 完成之前,outer 也可能还是 pending。
Promise 常用 API
构造函数
new Promise(executor)
executor 是执行器函数,签名如下:
要点:
executor会在创建 Promise 时立即同步执行resolve用于将状态变为fulfilledreject用于将状态变为rejected- 如果
executor内部抛出异常,Promise 会自动变为rejected executor的返回值会被忽略
输出:
实例方法
then()
方法签名:promise.then(onFulfilled, onRejected)
说明:
- 第一个参数在 Promise 变为
fulfilled时调用 - 第二个参数在 Promise 变为
rejected时调用 - 两个参数都是可选的
then()会立即返回一个新的 Promise,因此可以继续链式调用
返回值规则是理解链式调用的关键:
- 返回普通值:新的 Promise 会以这个值变为
fulfilled - 返回 Promise 或 thenable:新的 Promise 会跟随它的结果
- 抛出错误:新的 Promise 会变为
rejected
Promise.resolve(1)
.then((value) => value + 1)
.then((value) => Promise.resolve(value + 1))
.then((value) => {
console.log(value);
});
输出:
catch()
方法签名:promise.catch(onRejected)
catch() 用于指定失败时的回调,本质上可以理解为:
示例:
const promise = new Promise((resolve, reject) => {
reject("error");
});
promise.catch((error) => {
console.log(error);
});
finally()
方法签名:promise.finally(onFinally)
finally() 用于注册一个“无论成功还是失败都会执行”的回调。它常用于收尾逻辑,例如:
- 关闭 loading
- 清理资源
- 记录日志
需要注意:
finally()的回调不接收成功值或失败原因- 它也会返回一个新的 Promise
- 默认情况下,它不会改变前一个 Promise 的结果
- 但如果在
finally()中抛出错误,或返回一个被拒绝的 Promise,链就会变为失败
Promise.resolve("ok")
.finally(() => {
console.log("cleanup");
})
.then((value) => {
console.log(value);
});
输出:
静态方法
Promise.resolve()
方法签名:Promise.resolve(value)
作用:把一个值转换为 Promise。
规则:
- 如果
value本身就是 Promise,通常会直接返回它 - 如果
value是 thenable,对应的then会被调用 - 否则会返回一个以该值为结果的
fulfilledPromise
输出:
如果传入的是 Promise,那么返回值会跟随它的状态:
const promise = Promise.resolve(
new Promise((resolve) => {
resolve("done");
})
);
promise.then((value) => {
console.log(value);
});
Promise.reject()
方法签名:Promise.reject(reason)
作用:返回一个被拒绝的 Promise。
要点:
- 它总是返回一个
rejectedPromise - 传入什么,就把什么作为拒绝原因
- 即使传入的是一个 Promise,也不会展开它
输出:
传入 Promise 时:
const promise = Promise.reject(
new Promise((resolve) => {
resolve("ok");
})
);
promise.catch((reason) => {
console.log(reason);
});
这里拿到的 reason 就是那个 Promise 对象本身,而不是它内部的成功值。
Promise.all()
方法签名:Promise.all(iterable)
作用:并发执行多个 Promise,并在全部成功时得到结果。
规则:
- 所有输入都成功时,返回
fulfilled - 结果是一个数组,顺序与传入顺序一致
- 只要有一个失败,就会立刻返回
rejected - 拒绝原因是第一个失败的 Promise 的原因
const p1 = Promise.resolve("Hello");
const p2 = Promise.resolve("Nice");
const p3 = Promise.resolve("Meet");
Promise.all([p1, p2, p3]).then((value) => {
console.log(value);
});
输出:
有任意一个失败时:
const p1 = Promise.resolve("Hello");
const p2 = Promise.reject("Nice");
const p3 = Promise.reject("Meet");
Promise.all([p1, p2, p3]).catch((error) => {
console.log(error);
});
输出:
Promise.race()
方法签名:Promise.race(iterable)
作用:多个 Promise 中,谁先敲定结果,就采用谁的结果。
这里的“先”既可能是先成功,也可能是先失败。
const p1 = new Promise((resolve) => {
setTimeout(() => resolve("Hello"), 100);
});
const p2 = new Promise((resolve, reject) => {
setTimeout(() => reject("Nice"), 200);
});
Promise.race([p1, p2]).then(
(value) => {
console.log(value);
},
(error) => {
console.log(error);
}
);
输出:
Promise.allSettled()
方法签名:Promise.allSettled(iterable)
作用:等待所有 Promise 都有结果后,再统一返回每一项的状态。
特点:
- 不要求全部成功
- 一定会等到所有 Promise 都结束
- 返回结果中会明确标记每一项是成功还是失败
const p1 = Promise.resolve("Hello");
const p2 = Promise.reject("Nice");
const p3 = Promise.reject("Meet");
Promise.allSettled([p1, p2, p3]).then((value) => {
console.log(value);
});
输出:
[
{ status: 'fulfilled', value: 'Hello' },
{ status: 'rejected', reason: 'Nice' },
{ status: 'rejected', reason: 'Meet' }
]
Promise.any()
方法签名:Promise.any(iterable)
作用:只要有一个 Promise 成功,就返回这个最先成功的结果。
规则:
- 只关心“第一个成功”
- 如果全部失败,返回
rejected - 全部失败时,拒绝原因是一个
AggregateError
const p1 = Promise.resolve("Hello");
const p2 = Promise.reject("Nice");
const p3 = Promise.reject("Meet");
Promise.any([p1, p2, p3])
.then((value) => {
console.log(value);
})
.catch((error) => {
console.log(error);
});
输出:
如果全部失败:
const p1 = Promise.reject("Hello");
const p2 = Promise.reject("Nice");
const p3 = Promise.reject("Meet");
Promise.any([p1, p2, p3]).catch((error) => {
console.log(error instanceof AggregateError);
console.log(error.errors);
});
多个回调的情况
如果为同一个 Promise 绑定多个回调,那么这些回调都会执行。
也就是说,Promise 的结果一旦确定,后续再绑定上去的对应回调,也依然能够拿到这个结果。
const promise = Promise.resolve("ok");
promise.then((value) => {
console.log("第一个回调:", value);
});
promise.then((value) => {
console.log("第二个回调:", value);
});
状态变化和回调执行的先后
Promise 的状态先确定,对应回调才会执行。
可以这样理解:
- 如果在同步代码中调用
resolve()或reject(),状态会先变更,回调稍后执行 - 如果在异步任务中调用
resolve()或reject(),那就先等异步任务运行到那一刻,状态才发生变化,然后再执行回调
无论哪种情况,都可以记成一句话:先落定状态,再调度回调。