Promise 是 JavaScript 异步编程的正式抽象层,本质是封装 pending→fulfilled/rejected 状态迁移的异步容器;通过 then/catch 实现可组合、可中断、统一错误处理的链式流程。

Promise 不是语法糖,而是 JavaScript 异步编程的正式抽象层;它本身不消除回调,但通过状态机和规范化的 then / catch 接口,让异步流程可组合、可中断、可统一错误处理。
Promise 是什么:一个有状态的异步容器
Promise 本质是一个对象,内部封装了「未完成(pending)→ 成功(fulfilled)」或「失败(rejected)」的状态迁移过程。它不是立即执行的函数,也不是线程,更不是定时器——它的核心价值在于把异步操作的「结果交付时机」与「结果使用方式」解耦。
- 构造时必须传入一个执行器函数
executor,它会**立即同步执行**,且只执行一次 -
resolve和reject是 executor 的两个参数,调用它们才会触发状态变更 - 状态一旦变为
fulfilled或rejected,就不可逆,后续所有then/catch都只能读取该终态 - Promise 实例本身不存储值,而是通过
then的返回值产生新 Promise,形成链式结构
如何用 then 解决回调地狱:靠返回值而非嵌套
回调地狱的本质是「在回调里写回调」,根源在于每个异步操作都强制要求你立刻处理结果。Promise 的 then 改变了这个规则:它不要求你立刻消费结果,而是允许你返回一个新值或新 Promise,由下一级 then 继续处理。
fetch('/api/user')
.then(response => response.json())
.then(user => fetch(`/api/posts?uid=${user.id}`))
.then(response => response.json())
.then(posts => console.log(posts))
.catch(err => console.error('出错了', err));
- 每个
then的回调函数只专注一件事:转换上一步的结果,或发起下一个异步操作 - 如果回调返回的是普通值(如字符串、数字),下个
then会立即收到它;如果返回的是 Promise,下个then会等它 settle 后再执行 - 注意:
fetch成功响应不等于 HTTP 状态码 200,response.ok才是判断依据,否则会掉进「成功回调里抛错」的坑
为什么 catch 不能只放在最后:错误捕获有作用域
catch 实际是 then(undefined, onRejected) 的语法糖,它只会捕获「前一个 Promise 的 rejection」,而不是整条链路上所有可能的异常。中间某个 then 抛出同步错误(比如 JSON.parse(null)),或者返回了一个立刻 reject 的 Promise,都会被紧随其后的 catch 捕获,但跳过前面的 catch。
立即学习“Java免费学习笔记(深入)”;
- 常见错误:把
catch写在第一个then后面,以为能兜住所有后续错误 → 实际只捕获第一个请求失败 - 正确做法:要么每个关键
then后都接catch(适合需差异化处理的场景),要么统一放在链末(适合全局兜底) - 注意:
async/await中的try/catch行为与此一致——它捕获的是当前await表达式产生的 rejection,不是整个函数体
容易被忽略的三个细节
Promise 的行为边界比直觉中更严格,很多“看似合理”的写法会导致静默失败或意外阻塞:
-
Promise.resolve().then(() => { throw new Error('boom') })不会崩掉主线程,但错误会被丢弃,除非链上有catch - 多个
then注册在同一个 Promise 上,它们是并发执行的,不是排队等待前一个完成(因为每个then都返回新 Promise) -
Promise.all([p1, p2])在任意一个 reject 时就立刻 reject,如果需要全部结果(含失败),得用Promise.allSettled











