使用 Promise.withResolvers() 來簡化你將函式 Promise 化的實現~~

azoux發表於2024-06-13

引言

在JavaScript程式設計中,Promise 是一種處理非同步操作的常用機制。Promise 物件代表了一個尚未完成但預期將來會完成的操作的結果。在本文中,我們將探討如何透過使用 ES2024 的 Promise.withResolvers API 來最佳化我們的 Promise 實現。

現有實現的問題

首先,讓我們看一個簡單的示例,展示在沒有使用 Promise.withResolvers 時,如何實現一個函式,該函式在傳入的另一個函式執行完畢後2秒才返回結果:

const returnAfterTwoSeconds = (func, ...args) => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      try {
        resolve(func(...args));
      } catch (e) {
        reject(e);
      }
    }, 2000);
  });
};

雖然上述程式碼能夠正常工作,但它的巢狀層次較深,對於初次閱讀的人來說可能不夠直觀。

改進實現

為了提高程式碼的可讀性,我們可以對上述實現進行一些改進:

const returnAfterTwoSeconds = (func, ...args) => {
  let outerResolve = null;
  let outerReject = null;
  const promise = new Promise((resolve, reject) => {
    outerResolve = resolve;
    outerReject = reject;
  });

  setTimeout(() => {
    try {
      outerResolve(func(...args));
    } catch (e) {
      outerReject(e);
    }
  }, 2000);

  return promise;
};

在這個改進版本中,我們首先建立了一個 Promise 物件,並暫存了它的 resolvereject 方法。然後在 setTimeout 中呼叫這些方法,最後返回 Promise 物件。這樣,即使 setTimeout 中的回撥執行完畢,返回的 Promise 物件也會根據回撥的結果變為 resolved 或 rejected。

使用 Promise.withResolvers

現在,讓我們看看如何使用 Promise.withResolvers 來進一步簡化我們的程式碼:

const returnAfterTwoSeconds = (func, ...args) => {
  const { promise, resolve, reject } = Promise.withResolvers();

  setTimeout(() => {
    try {
      resolve(func(...args));
    } catch (e) {
      reject(e);
    }
  }, 2000);

  return promise;
};

可以看到,這個方法並沒有為我們的程式碼帶來效能或者說實現方式上的最佳化,但是它使用起來很簡單,也很好理解~ 有助於提高程式碼的可讀性和簡潔~

Promise.withResolvers 詳解

根據 MDN 文件Promise.withResolvers 的語法如下:

  • 語法:Promise.withResolvers()
  • 引數:無
  • 返回值:
    • promise: 一個 物件。
    • resolve: 一個函式,用於解決該 Promise。關於其語義,請參閱 建構函式。
    • reject: 一個函式,用於拒絕該 Promise。關於其語義,請參閱 建構函式。

自定義實現

最後,我們可以自定義一個函式來模擬 Promise.withResolvers 的行為:

function myWithResolvers() {
  let resolve = null;
  let reject = null;
  const promise = new Promise((_resolve, _reject) => {
    resolve = _resolve;
    reject = _reject;
  });

  return { promise, resolve, reject };
}

可以看到,這個api在實現上其實也很簡單,只是把我們平常獲取promise中resolve和reject的步驟封裝到一個方法中,但為我們節省了很多時間~

相關文章