Promise.prototype.finally()

1. 是什么?

finally() 方法返回一个 Promise。在 promise 结束时,无论结果是 fulfilled 或 rejected,都会执行指定的回调函数。这为"无论 Promise 是否成功都需执行的代码"提供了一种方式。

finally 无论 promise 成功还是失败都会被调用,且回调不接受任何参数;同时它会把原始值/异常透传给下一个 then/catch。

fetch(myRequest).finally(function () {
  isLoading = false;
});

finally 回调不接受任何参数(与 then / catch 不同),因为无法预知是成功还是失败。

2. 简单实现

Promise.prototype.finally = function (callback) {
  const P = this.constructor;
  return this.then(
    (value) => P.resolve(callback()).then(() => value),
    (reason) => P.resolve(callback()).then(() => { throw reason; })
  );
};
  • 关键点:callback() 也被包成 Promise,等它执行完再传递原本的 value / reason,这样 finally 不会"吞掉"错误。
  • 通过 this.constructor 拿到当前的 Promise 构造器,这样子类(如 MyPromise)继承 finally 时也能正确返回子类的实例。

3. 另一种实现(直接用 Promise.resolve)

如果不在乎子类继承,也可以写得更直观:

Promise.prototype.finally = function (callback) {
  return this.then(
    /* onFulfilled */
    (res) => Promise.resolve(callback()).then(() => res),
    /* onRejected */
    (err) => Promise.resolve(callback()).then(() => { throw err; })
  );
};

补充:原实现里 console.log(this) / console.log(promise) 是调试残留,promise 变量并未声明,运行时会报错;这里已删掉,只保留最终版实现。

4. 使用场景

  • 关闭加载状态:网络请求完成后无论成功失败都关闭 loading。
  • 清理资源:关闭连接、释放锁、移除事件监听。
  • 埋点:成功失败都要统计的指标上报。
function upload(file) {
  showLoading();
  return fetch('/upload', { method: 'POST', body: file })
    .then((res) => res.json())
    .catch((err) => ({ error: err.message }))
    .finally(() => hideLoading());
}

来源整理自:我的有道云笔记