Promise.prototype.finally()

Baseline 已廣泛支援

此特性已成熟穩定,適用於多種裝置和瀏覽器版本。自 2018 年 10 月起,它已在各瀏覽器中可用。

finally() 方法用於 Promise 例項,安排一個函式在 Promise 狀態確定(fulfilled 或 rejected)時被呼叫。它會立即返回另一個 Promise 物件,使你可以 鏈式呼叫 其他 Promise 方法。

這可以避免在 Promise 的 then()catch() 處理器中重複程式碼。

試一試

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
promiseInstance.finally(onFinally)

引數

onFinally

當此 Promise 狀態確定時非同步執行的函式。除非返回值是一個被拒絕的 Promise,否則其返回值將被忽略。該函式不帶任何引數呼叫。

返回值

立即返回一個新的 Promise。這個新 Promise 在返回時始終處於 pending 狀態,無論當前 Promise 的狀態如何。如果 onFinally 丟擲錯誤或返回一個被拒絕的 Promise,新 Promise 將以該值被拒絕。否則,新 Promise 將以與當前 Promise 相同的狀態確定。

描述

如果你想在 Promise 狀態確定後執行一些處理或清理工作,而不考慮其結果,那麼 finally() 方法會很有用。

finally() 方法非常類似於呼叫 then(onFinally, onFinally)。然而,有幾點不同:

  • 當內聯建立函式時,你可以只傳遞一次,而不是被迫宣告兩次,或者為它建立一個變數。
  • onFinally 回撥不接收任何引數。這種情況適用於你不關心拒絕原因或 fulfilled 值的情況,因此沒有必要提供它。
  • finally() 呼叫通常是透明的,並且反映了原始 Promise 的最終狀態。例如:
    • Promise.resolve(2).then(() => 77, () => {})(它返回一個最終 fulfilled 為 77 的 Promise)不同,Promise.resolve(2).finally(() => 77) 返回一個最終 fulfilled 為 2 的 Promise。
    • 同樣,與 Promise.reject(3).then(() => {}, () => 88)(它返回一個最終 fulfilled 為 88 的 Promise)不同,Promise.reject(3).finally(() => 88) 返回一個最終 rejected 為 3 的 Promise。

注意:finally 回撥中 throw(或返回一個被拒絕的 Promise)仍然會拒絕返回的 Promise。例如,Promise.reject(3).finally(() => { throw 99; })Promise.reject(3).finally(() => Promise.reject(99)) 都將返回的 Promise 以原因 99 拒絕。

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() 相同的演算法進行 resolve,但用於構造已 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® 2026 語言規範
# sec-promise.prototype.finally

瀏覽器相容性

另見