From 5780c0f8674e552e83ab2ae18819ba87efaf38fe Mon Sep 17 00:00:00 2001 From: robert-jx <129058738+robert-jx@users.noreply.github.com> Date: Mon, 3 Jul 2023 11:06:54 +0800 Subject: [PATCH] update the translation of `promise.finally()` (#13976) Co-authored-by: Jason Lam Co-authored-by: A1lo --- .../global_objects/promise/finally/index.md | 67 ++++++++++++++----- 1 file changed, 50 insertions(+), 17 deletions(-) diff --git a/files/zh-cn/web/javascript/reference/global_objects/promise/finally/index.md b/files/zh-cn/web/javascript/reference/global_objects/promise/finally/index.md index 6b41f1115f8d4c..c6999387888d8d 100644 --- a/files/zh-cn/web/javascript/reference/global_objects/promise/finally/index.md +++ b/files/zh-cn/web/javascript/reference/global_objects/promise/finally/index.md @@ -3,51 +3,83 @@ title: Promise.prototype.finally() slug: Web/JavaScript/Reference/Global_Objects/Promise/finally --- -{{JSRef}}**`finally()`** 方法返回一个 {{jsxref("Promise")}}。在 promise 结束时,无论结果是 fulfilled 或者是 rejected,都会执行指定的回调函数。这为在 `Promise` 是否成功完成后都需要执行的代码提供了一种方式。这避免了同样的语句需要在 {{jsxref("Promise.then", "then()")}} 和 {{jsxref("Promise.catch", "catch()")}} 中各写一次的情况。 +{{JSRef}} + +{{jsxref("Promise")}} 实例的 **`finally()`** 方法用于注册一个在 promise 敲定(兑现或拒绝)时调用的函数。它会立即返回一个等效的 {{jsxref("Promise")}} 对象,这可以允许你[链式](/zh-CN/docs/Web/JavaScript/Guide/Using_promises#链式调用)调用其他 promise 方法。 + +这可以让你避免在 promise 的 {{jsxref("Promise/then", "then()")}} 和 {{jsxref("Promise/catch", "catch()")}} 处理器中重复编写代码。 + +{{EmbedInteractiveExample("pages/js/promise-finally.html", "taller")}} ## 语法 ```js-nolint -p.finally(onFinally) +finally(onFinally) ``` ### 参数 - `onFinally` - - : `Promise` 结束后调用的 {{jsxref("Function")}}。 + - : 一个当 promise 敲定时异步执行的函数。它的返回值将被忽略,除非返回一个被拒绝的 promise。调用该函数时不带任何参数。 ### 返回值 -返回一个设置了 `finally` 回调函数的 {{jsxref("Promise")}} 对象。 +返回等效的 {{jsxref("Promise")}}。如果处理程序抛出错误或返回被拒绝的 promise,那么 `finally()` 返回的 promise 将以该值被拒绝。否则,处理程序的返回值不会影响原始 promise 的状态。 ## 描述 -如果你想在 promise 执行完毕后无论其结果怎样都做一些处理或清理时,`finally()` 方法可能是有用的。 +如果你想在 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。 + +> **备注:** 在 `finally` 回调函数中抛出错误(或返回被拒绝的 promise)仍会导致返回的 promise 被拒绝。例如,`Promise.reject(3).finally(() => { throw 99; })` 和 `Promise.reject(3).finally(() => Promise.reject(99))` 都以理由 `99` 拒绝返回的 promise。 -`finally()` 虽然与 `.then(onFinally, onFinally)` 类似,它们不同的是: +与 {{jsxref("Promise/catch", "catch()")}} 一样,`finally()` 在内部调用其调用对象上的 `then` 方法。如果 `onFinally` 不是函数,则调用 `then()` 时使用 `onFinally` 同时作为两个参数——对于 {{jsxref("Promise.prototype.then()")}},这意味着没有附加有效的处理器。否则,`then()` 被调用时会使用两个内部创建的函数,其行为如下: -- 调用内联函数时,不需要多次声明该函数或为该函数创建一个变量保存它。 -- 由于无法知道 `promise` 的最终状态,所以 `finally` 的回调函数中不接收任何参数,它仅用于无论最终结果如何都要执行的情况。 -- 与`Promise.resolve(2).then(() => {}, () => {})`(resolved 的结果为`undefined`)不同,`Promise.resolve(2).finally(() => {})` resolved 的结果为 `2`。 -- 同样,`Promise.reject(3).then(() => {}, () => {})` (fulfilled 的结果为`undefined`), `Promise.reject(3).finally(() => {})` rejected 的结果为 `3`。 +> **警告:** 这只是为了演示,而不是一个 polyfill。 -> **备注:** 在 `finally` 回调中 `throw`(或返回被拒绝的 promise)将以 `throw()` 指定的原因拒绝新的 promise. +```js +promise.then( + (value) => Promise.resolve(onFinally()).then(() => value), + (reason) => + Promise.resolve(onFinally()).then(() => { + throw reason; + }), +); +``` + +因为 `finally()` 调用 `then()`,所以它支持子类化。此外,请注意上面的 {{jsxref("Promise.resolve()")}} 调用——实际上,`onFinally()` 的返回值是使用与 `Promise.resolve()` 相同的算法解决的,但用于构造解决的 promise 的实际构造函数将是子类。`finally()` 通过 [`promise.constructor[@@species]`](/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise/@@species) 获取构造函数。 ## 示例 +### 使用 finally() + ```js let isLoading = true; -fetch(myRequest).then(function(response) { - var contentType = response.headers.get("content-type"); - if(contentType && contentType.includes("application/json")) { +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(function(json) { /* process your JSON further */ }) - .catch(function(error) { console.log(error); }) - .finally(function() { isLoading = false; }); + .then((json) => { + /* 进一步处理 JSON */ + }) + .catch((error) => { + console.error(error); // 这行代码也可能抛出错误,例如:when console = {} + }) + .finally(() => { + isLoading = false; + }); ``` ## 规范 @@ -60,6 +92,7 @@ fetch(myRequest).then(function(response) { ## 参见 +- [`core-js` 中 `Promise.prototype.finally` 的 Polyfill](https://github.com/zloirock/core-js#ecmascript-promise) - {{jsxref("Promise")}} - {{jsxref("Promise.prototype.then()")}} - {{jsxref("Promise.prototype.catch()")}}