Promise.finally 在当前 Promise 状态确定后立即作为微任务执行,不等待链结束或宏任务,只等同层 then/catch 微任务完成,且不改变传递值、不接收参数,适用于必须执行的清理操作。

Promise.finally 不是“链的最后才执行”,而是“当前 Promise 状态一确定就执行”——它作为微任务,在当前 Promise 实例变为 fulfilled 或 rejected 后,紧随其后对应的 then 或 catch 回调(如果存在且已入队)执行完毕时,立即进入微任务队列。
finally 在微任务队列中的确切位置
它不等待整个 Promise 链结束,也不等待后续异步操作(如 setTimeout、fetch 响应等),只等待:
- 当前 Promise 的状态已 settled(fulfilled/rejected)
- 同一层级上已注册的
then或catch回调(同步执行部分)完成 - 该
finally所属的 Promise 实例本身的处理流程走完(即它的微任务时机已到)
例如:
Promise.resolve()
.then(() => console.log('A'))
.finally(() => console.log('F'))
.then(() => console.log('B'));
输出顺序为:A → F → B。说明 finally 插在第一个 then 和第二个 then 之间,是链中一个确定的微任务节点,而非末尾兜底。
finally 不会等待宏任务,但会等待它前面的微任务
微任务队列优先级高于宏任务。即使你在 then 中启动了一个 setTimeout,finally 也会先执行:
-
Promise.resolve().then(() => setTimeout(console.log, 0, 'timer')).finally(() => console.log('finally'))→ 输出finally先于timer - 但如果
then返回一个新 Promise,finally会等那个 Promise settle 后再执行(因为它属于同一 Promise 链的延续)
finally 对值和错误的处理规则
它不接收参数,也不改变向下传递的值:
- 返回任意值(包括 Promise)都会被忽略,原始 Promise 的结果继续向后传递
- 若
finally回调里抛出错误,该错误会被后续catch捕获,但不影响原 Promise 的状态判定时机 - 即使前面的
then抛错、被catch拦截,finally依然会执行
典型适用场景:清理动作必须可靠触发
适合那些与成功/失败无关、但必须执行的操作:
- 关闭 loading 状态(如
isLoading = false) - 释放资源(如关闭 WebSocket、取消定时器句柄)
- 日志记录(“请求已结束”,不关心是否成功)
这些操作放在 then + catch 里容易遗漏或重复,而 finally 提供了语义清晰、执行可靠的单点入口。


















