Promise.prototype.finally()

基线 广泛可用

此功能已得到良好建立,并在许多设备和浏览器版本中都能正常工作。自以下时间起,它已在各个浏览器中可用 2018 年 10 月.

finally() 方法是 Promise 实例的一个方法,用于安排一个函数,在 promise 完成(fulfilled)或拒绝(rejected)时调用。它会立即返回另一个 Promise 对象,允许您链式调用其他 promise 方法。

这使您能够避免在 promise 的 then()catch() 处理程序中重复代码。

试一试

语法

js
promiseInstance.finally(onFinally)

参数

onFinally

一个函数,当此 promise 完成时异步执行。除非返回值是一个被拒绝的 promise,否则它的返回值会被忽略。该函数在没有参数的情况下被调用。

返回值

立即返回一个新的 Promise。无论当前 promise 的状态如何,此新 promise 在返回时始终处于挂起状态。如果 onFinally 抛出错误或返回一个被拒绝的 promise,则新 promise 将会拒绝并使用该值。否则,新 promise 将会与当前 promise 具有相同的状态。

描述

如果您希望在 promise 完成后进行一些处理或清理,无论其结果如何,finally() 方法都很有用。

finally() 方法与调用 then(onFinally, onFinally) 非常相似。但是,它们之间存在一些差异

  • 在内联创建函数时,您可以传递一次,而不是被迫声明两次或为其创建一个变量。
  • onFinally 回调不接收任何参数。此用例用于您不在乎拒绝原因或完成值的情况,因此无需提供它。
  • finally() 调用通常是透明的,并反映原始 promise 的最终状态。例如
    • Promise.resolve(2).then(() => 77, () => {}) 不同,后者返回一个最终以值 77 完成的 promise,Promise.resolve(2).finally(() => 77) 返回一个最终以值 2 完成的 promise。
    • 类似地,与 Promise.reject(3).then(() => {}, () => 88) 不同,后者返回一个最终以值 88 完成的 promise,Promise.reject(3).finally(() => 88) 返回一个最终以原因 3 拒绝的 promise。

注意:finally 回调中的 throw(或返回被拒绝的 promise)仍然会拒绝返回的 promise。例如,Promise.reject(3).finally(() => { throw 99; })Promise.reject(3).finally(() => Promise.reject(99)) 都以原因 99 拒绝返回的 promise。

catch() 一样,finally() 在内部对它被调用的对象调用 then 方法。如果 onFinally 不是函数,则 then() 会将 onFinally 作为两个参数调用——对于 Promise.prototype.then() 来说,这意味着没有附加任何有用的处理程序。否则,then() 会调用两个内部创建的函数,其行为如下

警告:这仅用于演示目的,不是 polyfill。

js
promise.then(
  (value) => Promise.resolve(onFinally()).then(() => value),
  (reason) =>
    Promise.resolve(onFinally()).then(() => {
      throw reason;
    }),
);

由于 finally() 调用 then(),因此它支持子类化。此外,请注意上面的 Promise.resolve() 调用——实际上,onFinally() 的返回值使用与 Promise.resolve() 相同的算法进行解析,但用于构造解析 promise 的实际构造函数将是子类。finally() 通过 promise.constructor[Symbol.species] 获取此构造函数。

示例

使用 finally()

js
let isLoading = true;

fetch(myRequest)
  .then((response) => {
    const contentType = response.headers.get("content-type");
    if (contentType && contentType.includes("application/json")) {
      return response.json();
    }
    throw new TypeError("Oops, we haven't got JSON!");
  })
  .then((json) => {
    /* process your JSON further */
  })
  .catch((error) => {
    console.error(error); // this line can also throw, e.g. when console = {}
  })
  .finally(() => {
    isLoading = false;
  });

规范

规范
ECMAScript 语言规范
# sec-promise.prototype.finally

浏览器兼容性

BCD 表格仅在启用 JavaScript 的浏览器中加载。

另请参阅