人人都会AI编程

then /catch/finally 方法

更新时间:2026-07-11

Promise 的核心价值在于用链式调用替代层层嵌套的回调函数,而 thencatchfinally 正是构建这条链的三块基石。理解它们的用法和返回值规则,是写出清晰异步代码的前提。

then — 处理“成功”与“失败”的统一入口

then 是 Promise 实例上最核心的方法,它接受两个可选的回调函数作为参数:

promise.then(onFulfilled, onRejected);
  • onFulfilled:当 Promise 状态变为 fulfilled(成功)时被调用,参数是 Promise 的结果值。
  • onRejected:当 Promise 状态变为 rejected(失败)时被调用,参数是 Promise 的拒绝原因。

两个参数都是可选的,如果传入的不是函数,会被忽略,并发生“值穿透”(稍后详述)。

关键规则:then 始终返回一个新的 Promise
这是链式调用的根基。无论 onFulfilled 还是 onRejected 内部返回什么值,then 都会将其包装成一个新的 Promise,传递给链上的下一个 then

fetch('/api/user')
  .then(response => response.json())    // 返回新 Promise
  .then(user => {
    console.log(user.name);             // 处理上一个 then 的结果
    return user.id;                     // 返回值会传递给下一个 then
  })
  .then(id => fetch(`/api/orders/${id}`))
  .then(orders => console.log(orders));

如果在 then 的回调中手动返回一个 Promise,那么后续的 then 会等待这个 Promise 完成,并拿它的结果继续。如果回调中抛出异常,then 会返回一个 rejected 的 Promise,直接跳转到后续的 catch

catch — 错误集中捕获

catch 实质上是 then(undefined, onRejected) 的语法糖,专门用来处理链中任何一个环节抛出的错误。推荐把 catch 放在链的末尾,这样无需在每个 then 中写错误处理逻辑。

fetch('/api/data')
  .then(res => res.json())
  .then(data => processData(data))
  .catch(error => {
    console.error('请求或处理过程中出错:', error);
    // 可以做统一错误提示、上报等
  });

错误会穿透:如果链中间某个 then 没有提供 onRejected 回调,错误会自动沿着链向下传递,直到遇到第一个 catch。这意味着你可以把错误处理集中在一处,而不用在每个环节都写一遍。

需要注意的是,catch 也会返回一个新的 Promise。如果 catch 内部正常返回一个值,链可以继续正常执行。利用这一点可以实现错误恢复:

fetch('/api/backup')
  .then(res => res.json())
  .catch(err => {
    console.warn('主请求失败,使用默认数据');
    return { name: '默认用户' };    // 返回了一个兜底值
  })
  .then(data => console.log(data));  // 始终能拿到 data

finally — 无论如何都会执行

finally 中的回调会在 Promise 敲定(无论是 fulfilled 还是 rejected) 之后执行,它不接受任何参数,也不影响最终结果的传递。典型的用途是清理工作:隐藏加载动画、关闭数据库连接、停止计时器等。

let loading = true;

fetch('/api/data')
  .then(res => res.json())
  .then(data => render(data))
  .catch(err => showError(err))
  .finally(() => {
    loading = false;   // 无论成功还是失败,都要关闭加载状态
  });

finally 也会返回一个新的 Promise,除非 finally 回调内部抛出错误,否则它会“原样传递”前一个 Promise 的结果或拒绝。这意味着写在 finally 后面的 thencatch 仍然能拿到原始的结果。

Promise.resolve('成功')
  .finally(() => '这个值会被忽略')  // 不改变结果
  .then(console.log);               // 输出:成功

Promise.reject('失败')
  .finally(() => '忽略')
  .catch(console.log);              // 输出:失败

值穿透与链式调用总结

then / catch 接收到的参数不是函数时,会发生“值穿透”,即前一个 Promise 的状态和值会直接传递到下一个有效处理函数:

Promise.resolve(42)
  .then(1)          // 不是函数,忽略
  .then(null)       // 不是函数,忽略
  .then(value => console.log(value)); // 42

理解以上规则后,任何复杂的异步流程都可以用一条清晰的 Promise 链来表达,而且错误处理和清理逻辑天然内聚,再也不需要嵌套的回调地狱。