Promise.try()

基準線 2025
新推出

自 ⁨2025 年 1 月⁩ 起,此功能在最新的裝置和瀏覽器版本中均可正常工作。此功能可能無法在舊裝置或瀏覽器中工作。

Promise.try() 靜態方法接受任何型別的回撥函式(可以返回值或丟擲異常,同步或非同步),並將其結果封裝在一個 Promise 中。

語法

js
Promise.try(func)
Promise.try(func, arg1)
Promise.try(func, arg1, arg2)
Promise.try(func, arg1, arg2, /* …, */ argN)

引數

func

一個同步呼叫的函式,並附帶提供的引數(arg1, arg2, …, argN)。它可以做任何事情——返回值、丟擲異常或返回一個 promise。

arg1, arg2, …, argN

要傳遞給 func 的引數。

返回值

一個 Promise,它

  • 如果 func 同步返回值,則為已解決。
  • 如果 func 同步丟擲異常,則為已拒絕。
  • 如果 func 返回一個 promise,則為非同步解決或拒絕。

描述

您可能有一個接受回撥函式的 API。該回調函式可能是同步的或非同步的。您希望透過將結果封裝在 promise 中來統一處理所有內容。最直接的方法可能是 Promise.resolve(func())。問題是,如果 func() 同步丟擲異常,該異常將不會被捕獲並轉換為已拒絕的 promise。

常見的做法(將函式呼叫的結果提升為 promise,已解決或已拒絕)通常如下所示:

js
new Promise((resolve) => resolve(func()));

Promise.try() 在這裡更有幫助

js
Promise.try(func);

對於內建的 Promise() 建構函式,從執行器丟擲的異常會自動捕獲並轉換為拒絕,因此這兩種方法在大多數情況下是等效的,只是 Promise.try() 更簡潔易讀。

請注意,Promise.try() 等同於此,儘管它們非常相似。

js
Promise.resolve().then(func);

區別在於傳遞給 then() 的回撥函式始終是非同步呼叫的,而 Promise() 建構函式的執行器是同步呼叫的。Promise.try 也同步呼叫函式,並在可能的情況下立即解析 promise。

Promise.try() 結合 catch()finally(),可以用來在單個鏈中處理同步和非同步錯誤,使 promise 的錯誤處理看起來幾乎像同步錯誤處理。

setTimeout() 一樣,Promise.try() 接受額外的引數,這些引數會傳遞給回撥函式。這意味著,與其這樣做

js
Promise.try(() => func(arg1, arg2));

您可以這樣做

js
Promise.try(func, arg1, arg2);

這兩者是等效的,但後者避免了建立額外的閉包,並且效率更高。

示例

使用 Promise.try()

以下示例接受一個回撥函式,“提升”它到 promise,處理結果,並進行一些錯誤處理

js
function doSomething(action) {
  return Promise.try(action)
    .then((result) => console.log(result))
    .catch((error) => console.error(error))
    .finally(() => console.log("Done"));
}

doSomething(() => "Sync result");

doSomething(() => {
  throw new Error("Sync error");
});

doSomething(async () => "Async result");

doSomething(async () => {
  throw new Error("Async error");
});

在 async/await 中,相同的程式碼將如下所示:

js
async function doSomething(action) {
  try {
    const result = await action();
    console.log(result);
  } catch (error) {
    console.error(error);
  } finally {
    console.log("Done");
  }
}

對非 Promise 建構函式呼叫 try()

Promise.try() 是一個通用方法。它可以被呼叫在任何實現與 Promise() 建構函式相同簽名的建構函式上。

以下是實際 Promise.try() 的一個更忠實的近似(儘管它仍然不應該用作 polyfill)

js
Promise.try = function (func) {
  return new this((resolve, reject) => {
    try {
      resolve(func());
    } catch (error) {
      reject(error);
    }
  });
};

由於 Promise.try() 的實現方式(即 try...catch),我們可以安全地將 Promise.try()this 設定為任何自定義建構函式,它永遠不會同步丟擲異常。

js
class NotPromise {
  constructor(executor) {
    // The "resolve" and "reject" functions behave nothing like the native
    // promise's, but Promise.try() just calls resolve
    executor(
      (value) => console.log("Resolved", value),
      (reason) => console.log("Rejected", reason),
    );
  }
}

const p = Promise.try.call(NotPromise, () => "hello");
// Logs: Resolved hello

const p2 = Promise.try.call(NotPromise, () => {
  throw new Error("oops");
});
// Logs: Rejected Error: oops

Promise() 不同,這個 NotPromise() 建構函式在執行執行器時*不會*優雅地處理異常。但是,儘管有 throwPromise.try() 仍然會捕獲異常,並將其傳遞給 reject() 進行輸出。

規範

規範
ECMAScript® 2026 語言規範
# sec-promise.try

瀏覽器相容性

另見