一、Promise 是什么(不是'异步回调的语法糖')
Promise 是 JavaScript 中用于处理异步操作的对象,它代表了一个异步操作的最终完成(或失败)及其结果值。
一句话本质:
Promise 是一个'状态机 + 回调管理器',用来描述'一个未来才会确定结果的值'。
Promise 的三大特征(规范层面)
- pending(进行中):初始状态
- fulfilled(已成功):操作成功完成
- rejected(已失败):操作失败
- 状态不可逆
状态转换是单向的:pending → fulfilledpending → rejected- 一旦改变,永远不可再变
then 永远异步执行(微任务)
即使 resolve 是同步调用的
结果值只认第一次
resolve(1)
resolve(2)// 无效
reject(3)// 无效
那为什么总说'Promise resolved 了'?(关键)
Promise 真正的'官方状态'只有 3 个
Promise/A+ & ECMAScript 规范中:
pending fulfilled rejected
✅ 没有 resolved 这个状态
resolved ≠ fulfilled
resolved 是一个'动词 / 过程',不是状态
规范里的原话是:
Resolve a promise with x
意思是:
尝试用某个值 x 去'解析(resolve)'Promise
用一句话精确区分(面试级)
resolved 表示 Promise 已经'被处理过',
但它最终可能是 fulfilled,也可能是 rejected
换句话说:
resolved ↓ fulfilled 或 rejected
⚠️ 注意:
一旦进入 resolved 流程,就不再是 pending
日常口语表达(工程师黑话)
'这个 Promise resolve 了'
通常真正意思是:
- then 被触发了
- 异步成功了
- 不是 pending 了
👉 不是规范用语
一个非常容易被问懵的面试题
Q:Promise.resolve(Promise.reject(1)) 的状态是什么?
Promise.resolve(Promise.reject(1)).then(()=> console.log('fulfilled'),err=> console.log('rejected', err))
正确理解:
- 外层 Promise 被 resolve 了
- 但 resolve 的值是一个 rejected Promise
- 所以最终状态是:
rejected(1)
⚠️ 这就是 'resolved ≠ fulfilled' 的最好例子
创建 Promise
const promise = new Promise((resolve, reject)=>{
// 异步操作
setTimeout(()=>{
const success = true;
if(success){
resolve('操作成功');
}else{
reject(new Error('操作失败'));
}
},1000);
});
二、Promise 的状态模型(核心)
┌─────────────┐
│ pending │
└──────┬──────┘
│
┌──────┴──────┐
│ │
┌───────────┐ ┌───────────┐
│ fulfilled │ │ rejected │
└───────────┘ └───────────┘
内部必然有的字段(实现角度)
{
status:'pending'|'fulfilled'|'rejected',
value: any,
reason: any,
onFulfilledCallbacks:[],
onRejectedCallbacks:[]
}
这不是猜的,是 Promise/A+ 实现的必然结构
三、Promise 的常见方法
then() - 处理成功和失败
then 方法可以接受两个回调函数作为参数。第一个回调函数是 Promise 对象的状态变为 fulfilled 时调用,第二个回调函数是 Promise 对象的状态变为 rejected 时调用。then 方法返回的是一个新的 Promise 对象实例;因此可以用链式写法,即 then 的后面再调用另一个 then 方法。
promise.then((result)=>{
console.log('成功:', result);
},(error)=>{
console.log('失败:', error);
});
catch() - 捕获错误
相当于第二个回调函数指向 reject;catch 方法还有一个作用,就是在执行 resolve 回调时,如果出现错误抛出异常,不会停止运行,而是进入 catch 方法中。
promise .then(result=> console.log(result)).catch(error=> console.error('错误:', error));
finally() - 无论成功失败都执行
finally 方法用于指定不管 Promise 对象最后状态如何,都会执行 finally。finally 方法的回调函数不接收任何参数。这表明 finally 方法里面的操作应与状态无关,不依赖于 Promise 的执行结果。
promise .then(result=> console.log(result)).catch(error=> console.error(error)).finally(()=> console.log('操作结束'));
all() - 所有都成功
方法接收一个平行任务。它接收一个数组;数组的每一项都是一个 Promise 对象;当数组的每一项的状态都是 fulfilled 的时候,all 方法的状态会变成 fulfilled。如果有一项状态变成 rejected,那么 all 方法的状态就会变成 rejected
- 全部 fulfilled → fulfilled(数组)
- 任意 rejected → 立即 rejected(短路)
const p1 = Promise.resolve(1);
const p2 = Promise.resolve(2);
const p3 = Promise.resolve(3);
Promise.all([p1, p2, p3]).then(values=> console.log(values));// [1, 2, 3]
.catch(error=> console.error(error));
race() - 最先完成的
和 all 方法一样,接收的参数是一个每项都是 Promise 的数组。但是与 all 不同的是,当最先执行的事件完成之后,就直接返回 Promise 对象的值,如果第一个 Promise 对象状态是 fulfilled,那自身状态就是 fulfilled。
- 谁先 settle,用谁
const p1 = new Promise(resolve=>setTimeout(resolve,500,'快'));
const p2 = new Promise(resolve=>setTimeout(resolve,1000,'慢'));
Promise.race([p1, p2]).then(value=> console.log(value));// "快"
any() - 任意一个成功
只要参数实例有一个变成 fulfilled 状态,包装实例就会变成 fulfilled 状态;如果所有参数实例都变成 rejected 状态,包装实例就会变成 rejected 状态。
Promise.any() 跟 Promise.race() 方法很像,只有一点不同,就是 Promise.any() 不会因为某个 Promise 变成 rejected 状态而结束,必须等到所有参数 Promise 变成 rejected 状态才会结束。
- 任意 fulfilled → fulfilled
- 全 rejected → rejected(AggregateError)
Promise.any([p1, p2]).then(value=> console.log(value));
四、then 的真正含义(99% 的人理解错)
then ≠ 注册回调这么简单
p.then(onFulfilled, onRejected)
then 做了 3 件极其重要的事:
- 返回一个新的 Promise(链式调用的根源)
- 把回调包装成'微任务'
- 处理返回值,决定新 Promise 的状态
then 的返回规则(重点)
| then 回调返回值 | 新 Promise 状态 |
|---|---|
| 普通值 | fulfilled,值为返回值 |
| Promise | 等这个 Promise |
| thenable 对象 | 按 Promise 解析 |
| throw error | rejected |
| 不写回调 | 值穿透 / 错误冒泡 |
Promise.resolve(1).then(v=> v +1).then(v=> Promise.resolve(v +1)).then(v=>{
throw 'err'
}).catch(e=> console.log(e))
五、Promise 链为什么不会'嵌套地狱'?
核心原因:then 返回新 Promise
const p2 = p1.then(...)
本质结构:
p1 ──then──▶ p2 ──then──▶ p3
而不是:
p1 └── then └── then └── then
Promise Resolution Procedure(规范核心)
伪代码:
if(x === promise) throw TypeError
if(x is Promise) adopt its state
if(x is object/function&& has then) call then
else resolve(x)
这套规则就是防止循环引用、防止多次 resolve、防止同步 thenable 乱入
六、Promise 的微任务本质(Event Loop 级别)
经典面试题
console.log(1)
Promise.resolve().then(()=>{
console.log(2)
})
setTimeout(()=>{
console.log(3)
})
console.log(4)
输出顺序:
1 4 2 3
原因
- Promise.then → Microtask
- setTimeout → Macrotask
async / await 本质
async function foo(){
await bar()
console.log(1)
}
等价于:
function foo(){
return Promise.resolve(bar()).then(()=>{
console.log(1)
})
}
👉 await = Promise.then 的语法糖
七、Promise 的'错误传播机制'
错误冒泡规则
throw等价于reject- 下游
then没有 onRejected → 继续向下冒泡 .catch()本质是.then(null, onRejected)
Promise.resolve().then(()=>{
throw new Error('boom')
}).then(()=>{
console.log('never')
}).catch(err=>{
console.log(err.message)
})
一个隐蔽坑(非常高级)
Promise.resolve().then(()=>{
setTimeout(()=>{
throw new Error('boom')
})
}).catch(()=>{
console.log('catch?')
})
👉 catch 不会捕获
原因:
Promise 只能捕获 then 链中的同步异常 & 返回的 Promise 异常
八、Promise 的核心(面试杀器)
不要求背,但必须理解
最小核心能力:
then(onFulfilled, onRejected){
return new Promise((resolve, reject)=>{
// 状态判断
// 回调队列
// 微任务包装
// 返回值处理(Promise Resolution)
})
}
面试官真正想问的是:
- 你理解'状态不可逆'吗?
- 你知道 then 为什么返回新 Promise 吗?
- 你明白微任务队列吗?
- 你理解 Promise Resolution Procedure 吗?
九、什么时候不该用 Promise(架构视角)
Promise 的局限性
- 无法取消 Promise,中途无法取消
- 错误处理需要谨慎;如果不设置回调函数,Promise 的内部抛出的错误不会反映到外部
- 需要配合 async/await 使用更佳
- 当处于 pending 状态时,无法得知目前进行到哪个阶段了
❌ 滥用 Promise:
- 复杂流程控制(应使用 async/await + try/catch)
- 大量并发控制(应配合并发池)
- 事件型逻辑(Promise 不可多次 resolve)
✅ Promise 最适合:
- 一次性结果
- IO 抽象
- 组合式异步
十、总结
Promise 是现代 JavaScript 异步编程的核心,理解它的工作原理和最佳实践对于编写健壮的异步代码至关重要。
Promise 解决的不是'异步',而是
'用可组合、可推理的方式描述未来值的状态变化'

