promise链式调用顺次执行靠微任务队列fifo机制:每个.then返回新promise并注册回调为微任务,按入队顺序在宏任务间隙执行;错误会穿透至最近.catch。

Promise 的 .then 链式调用之所以能“顺次执行”,核心不是靠代码书写顺序,而是靠微任务(microtask)队列的排队与逐个清空机制。每次 .then 返回新 Promise,都会把后续回调注册为一个微任务;这些微任务被依次推入队列,并在当前宏任务结束后、下一个宏任务开始前,按先进先出(FIFO)顺序同步执行。
每个 .then 都生成一个新 Promise
这是链式调用成立的前提:
-
promise.then(fn)总是返回一个全新的 Promise 实例,与原 Promise 无关 - 新 Promise 的状态由
fn的执行结果决定:返回普通值 → 立即 resolve;抛错或返回 rejected Promise → 新 Promise reject - 即使
fn是空函数或只写return;,也会 resolve 为undefined
回调实际以微任务形式排队
你写的 .then(() => console.log(1)) 并不会立刻执行,而是:
- 当上一个 Promise 变为 fulfilled,引擎会把该
.then的回调加入微任务队列(queueMicrotask) - 当前同步脚本执行完后,JS 引擎立即清空整个微任务队列——一个接一个执行,不插队、不中断
- 如果某个回调里又返回 Promise(比如
return fetch(...)),它的.then回调会在该 Promise settle 后,再作为**新的微任务**追加到队列末尾
多个独立链之间不保证绝对顺序
下面三行代码看似并列,但微任务入队和执行存在细微时序差异:
Promise.resolve().then(() => console.log(1)).then(() => console.log(2)); Promise.resolve().then(() => console.log(11)).then(() => console.log(12)); Promise.resolve().then(() => console.log(111));
输出可能是 1 → 11 → 111 → 2 → 12,而非严格按行号排列。原因在于:
- 三行
Promise.resolve()几乎同时执行,各自第一个.then回调几乎同时入微任务队列 - 它们的执行顺序取决于入队先后(通常就是书写顺序),但后续的
.then(如console.log(2))是在前一个回调执行完、返回新 Promise 并 settle 后,才作为新微任务加入队列末尾 - 所以
2和12谁先入队,取决于1和11哪个回调先执行完——而这个时间差极小,不可预测
错误会穿透,.catch 统一捕获
链中任意环节 throw 错误、返回 rejected Promise 或 Promise 被 reject,都会跳过后续所有 onFulfilled 回调,直接找到最近的 .catch 或 .then(null, onRejected):
- 这种“错误冒泡”依赖微任务机制:reject 发生时,引擎同样把对应的 rejection 处理器作为微任务入队
- 哪怕中间隔着多个
.then,只要没显式处理,错误就会一路向后,直到被.catch拦截 -
.catch本身也返回 Promise,因此还能继续链式调用(例如恢复流程:.catch(() => Promise.resolve('fallback')))











