js Promise 是什么怎么使用
Promise 是表示异步操作最终结果的对象,讲解其 pending、fulfilled、rejected 三态不可逆,then、catch、finally 的链式用法与 async/await 推荐写法,并说明 all、allSettle
Promise 是 JavaScript 中表示「一个尚未完成、但将来会有结果(成功或失败)的异步操作」的对象。它的核心价值是把层层嵌套的回调改写成链式调用:用 new Promise 创建,用 then/catch/finally 消费结果,日常开发里更推荐配合 async/await 写。
Promise 是什么?三个状态怎么理解
结论:Promise 只有三种状态——pending(进行中)、fulfilled(已成功)、rejected(已失败),状态一旦从 pending 变成 fulfilled 或 rejected,就永久固定、不可逆转。
const p = new Promise((resolve, reject) => {
// 执行器函数是同步执行的
setTimeout(() => resolve('ok'), 1000)
})
console.log(p) // Promise { <pending> }
注意两点:new Promise(executor) 里的 executor 是同步立即执行的,只有 resolve/reject 的结果才是异步交付;then 的回调属于微任务(microtask),会在当前同步代码和 setTimeout 之前执行。
console.log(1)
Promise.resolve().then(() => console.log(3))
setTimeout(() => console.log(4))
console.log(2)
// 输出顺序:1 2 3 4
Promise 怎么使用?基本写法
结论:用 then 拿成功值,用 catch 抓错误,链式调用中任意一环 return 的值都会成为下一个 then 的入参。
fetch('/api/user')
.then(res => res.json())
.then(data => {
console.log(data.name)
return fetch('/api/order')
})
.then(res => res.json())
.catch(err => console.error('任一环节出错都会到这里:', err))
.finally(() => console.log('无论成功失败都执行'))
关键点:catch 能捕获整条链上前面任意一环抛出的错误,所以链尾放一个 catch 就够了;如果 then 里 return 的是一个新的 Promise,链会等它完成再往下走,这就是「串行异步」的标准写法。
then、catch、finally 有什么区别
结论:then 接收成功和失败两个回调,catch(fn) 等价于 then(null, fn),finally 不接收参数、也不改变结果,只用于收尾。
finally 的返回值会被忽略(除非它返回一个 rejected 的 Promise),适合放 loading 关闭、连接释放这类清理逻辑。另外 then 的成功回调里 throw 的错误,不会传给同一个 then 的第二个参数,而是传给下一个 catch——这是新手最容易踩的坑。
Promise.all、allSettled、race、any 怎么选
结论:要全部成功用 Promise.all,要拿到全部结果(不管成败)用 Promise.allSettled,要最快返回用 Promise.race,要第一个成功用 Promise.any。
| 方法 | 成功条件 | 失败条件 | 返回 |
|---|---|---|---|
Promise.all | 全部 fulfilled | 任一 rejected 就立刻 reject | 结果数组,顺序与传入一致 |
Promise.allSettled | 等全部结束 | 不会 reject | {status, value/reason} 数组 |
Promise.race | 第一个 settled | 第一个是 rejected 就 reject | 第一个结束的值 |
Promise.any | 第一个 fulfilled | 全部 rejected 才 reject(AggregateError) | 第一个成功的值 |
Promise.all 的返回顺序跟传入顺序一致,不是完成顺序,但它有一个特性要记住:只要有一个失败就立即 reject,其它 Promise 并不会被取消,仍在后台继续跑。
async/await 和 Promise 是什么关系
结论:async/await 是 Promise 的语法糖,async 函数一定返回 Promise,await 后面可以跟任意 thenable。
async function load() {
try {
const res = await fetch('/api/user')
return await res.json()
} catch (e) {
console.error(e)
}
}
load().then(data => console.log(data))
await 会让出执行权,但只暂停当前 async 函数的内部流程,不阻塞主线程。用 try/catch 代替 .catch() 时,要包住每一个可能抛错的 await。另外在 for 循环里 await 是串行执行,想并发就用 await Promise.all(list.map(...))。
常见坑与结论汇总
结论:Promise 的坑集中在「忘记 return」和「不处理 rejection」两处。
- 在
.then里忘记return,下一个then拿到的是undefined,异步也没被等待; - 没有
.catch的 rejection 会触发unhandledrejection事件,Node.js 中可能导致进程退出; Promise一旦创建就会立即执行,无法取消,需要中断要自己用AbortController配合fetch;new Promise里如果同步抛错,Promise 会变成 rejected,而不是向外抛出。
一句话收束:Promise 用三种不可逆状态统一了异步结果的表达,日常写法是 async/await + try/catch,并发场景按「全成功 / 全结束 / 最快 / 首个成功」四种需求分别选 all、allSettled、race、any,最需要警惕的是链中漏掉 return 和漏掉错误处理。
转载请注明出处,版权归原作者所有。