Promise 实例的 finally() 方法用于注册一个在 promise 敲定(兑现或拒绝)时调用的函数。它会立即返回一个等效的 Promise 对象,这可以允许你链式调用其他 promise 方法。
这可以让你避免在 promise 的 {{jsxref("Promise/then", "then()")}} 和 {{jsxref("Promise/catch", "catch()")}} 处理器中重复编写代码。
{{InteractiveExample("JavaScript Demo: Promise.finally()", "taller")}}
```js interactive-example function checkMail() { return new Promise((resolve, reject) => { if (Math.random() > 0.5) { resolve("Mail has arrived"); } else { reject(new Error("Failed to arrive")); } }); }
checkMail() .then((mail) => { console.log(mail); }) .catch((err) => { console.error(err); }) .finally(() => { console.log("Experiment completed"); });
## 语法
```js-nolint
finally(onFinally)
参数
onFinally- : 一个当 promise 敲定时异步执行的函数。它的返回值将被忽略,除非返回一个被拒绝的 promise。调用该函数时不带任何参数。
返回值
立即返回一个新的 Promise。无论当前 promise 的状态如何,此新的 promise 在返回时始终处于待定(pending)状态。如果 onFinally 抛出错误或返回被拒绝的 promise,则新的 promise 将使用该值进行拒绝。否则,新的 promise 将以与当前 promise 相同的状态敲定(settled)。
描述
如果你想在 promise 敲定时进行一些处理或者清理,无论其结果如何,那么 finally() 方法会很有用。
finally() 方法类似于调用 {{jsxref("Promise/then", "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。
- 与
[!NOTE] 在
finally回调函数中抛出错误(或返回被拒绝的 promise)仍会导致返回的 promise 被拒绝。例如,Promise.reject(3).finally(() => { throw 99; })和Promise.reject(3).finally(() => Promise.reject(99))都以理由99拒绝返回的 promise。
与 {{jsxref("Promise/catch", "catch()")}} 一样,finally() 在内部调用其调用对象上的 then 方法。如果 onFinally 不是函数,则调用 then() 时使用 onFinally 同时作为两个参数——对于 Promise.prototype.then(),这意味着没有附加有效的处理器。否则,then() 被调用时会使用两个内部创建的函数,其行为如下:
[!WARNING] 这只是为了演示,而不是一个 polyfill。
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()
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) => {
/* 进一步处理 JSON */
})
.catch((error) => {
console.error(error); // 这行代码也可能抛出错误,例如:when console = {}
})
.finally(() => {
isLoading = false;
});