Promise.prototype.finally()

Baseline Widely available

This feature is well established and works across many devices and browser versions. It’s been available across browsers since October 2018.

Promise 实例的 finally() 方法安排一个函数在承诺完成(履行或拒绝)时调用。它立即返回另一个 Promise 对象,允许你对其他承诺方法进行 chain 调用。

¥The finally() method of Promise instances schedules a function to be called when the promise is settled (either fulfilled or rejected). It immediately returns another Promise object, allowing you to chain calls to other promise methods.

这可以让你避免在 Promise 的 then()catch() 处理程序中重复代码。

¥This lets you avoid duplicating code in both the promise's then() and catch() handlers.

Try it

语法

¥Syntax

js
promiseInstance.finally(onFinally)

参数

¥Parameters

onFinally

当此承诺得到解决时异步执行的函数。除非返回值是被拒绝的 Promise,否则它的返回值将被忽略。调用该函数时不带参数。

返回值

¥Return value

立即返回新的 Promise。无论当前 Promise 的状态如何,该新 Promise 在返回时始终处于待处理状态。如果 onFinally 抛出错误或返回被拒绝的 Promise,则新的 Promise 将以该值拒绝。否则,新的 Promise 将以与当前 Promise 相同的状态进行结算。

¥Returns a new Promise immediately. This new promise is always pending when returned, regardless of the current promise's status. If onFinally throws an error or returns a rejected promise, the new promise will reject with that value. Otherwise, the new promise will settle with the same state as the current promise.

描述

¥Description

如果你想要在承诺解决后进行一些处理或清理(无论其结果如何),则 finally() 方法可能很有用。

¥The finally() method can be useful if you want to do some processing or cleanup once the promise is settled, regardless of its outcome.

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

¥The finally() method is very similar to calling then(onFinally, onFinally). However, there are a couple of differences:

  • 创建内联函数时,你可以传递一次,而不是被迫声明两次或为其创建一个变量。
  • onFinally 回调不接收任何参数。此用例恰好适用于你不关心拒绝原因或履行价值的情况,因此无需提供它。
  • finally() 调用通常是透明的,反映了原始承诺的最终状态。例如:
    • Promise.resolve(2).then(() => 77, () => {}) 返回最终用值 77 实现的承诺不同,Promise.resolve(2).finally(() => 77) 返回最终用值 2 实现的承诺。
    • 类似地,与 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)) 都拒绝返回的 promise,原因为 99

¥Note: A throw (or returning a rejected promise) in the finally callback still rejects the returned promise. For example, both Promise.reject(3).finally(() => { throw 99; }) and Promise.reject(3).finally(() => Promise.reject(99)) reject the returned promise with the reason 99.

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

¥Like catch(), finally() internally calls the then method on the object upon which it was called. If onFinally is not a function, then() is called with onFinally as both arguments — which, for Promise.prototype.then(), means that no useful handler is attached. Otherwise, then() is called with two internally created functions, which behave like the following:

警告:这仅用于演示目的,而不是填充。

¥Warning: This is only for demonstration purposes and is not a 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] 得到这个构造函数。

¥Because finally() calls then(), it supports subclassing. Moreover, notice the Promise.resolve() call above — in reality, onFinally()'s return value is resolved using the same algorithm as Promise.resolve(), but the actual constructor used to construct the resolved promise will be the subclass. finally() gets this constructor through promise.constructor[Symbol.species].

示例

¥Examples

使用 finally()

¥Using 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;
  });

规范

Specification
ECMAScript Language Specification
# sec-promise.prototype.finally

¥Specifications

浏览器兼容性

BCD tables only load in the browser

¥Browser compatibility

也可以看看