點燈坊

失くすものさえない今が強くなるチャンスよ

使用 timeout() 實現 Timeout Promise

Sam Xiao's Avatar 2019-09-27

由於 Asynchronous 回傳結果時間不確定,Wink-fp 的 timeout() 能產生指定時間的 rejected promise,若實際 Promise 晚於 Timeout Promise 則放棄,改回傳 rejected promise。

Version

macOS Mojave 10.14.6
VS Code 1.38.1
Quokka 1.0.253
ECMAScript 2015
Wink-fp 0.0.22

Promise.race()

let resolveAfter = ms => val => new Promise(resolve => setTimeout(() => resolve(val), ms));

let promise0 = resolveAfter(1000)('Sam');
let promise1 = resolveAfter(2000)('Jessie');

let fatestPromise = Promise.race([ promise0, promise1 ]);

fatestPromise.then(x => console.log(x));

第 1 行

let resolveAfter = ms => val => new Promise(resolve => setTimeout(() => resolve(val), ms));

先實作 resolveAfter(),能 asynchronous 地在幾 ms 後產生 promise 用來測試 Promise.race()

第 3 行

let promise0 = resolveAfter(1000)('Sam');
let promise1 = resolveAfter(2000)('Jessie');

let fatestPromise = Promise.race([ promise0, promise1 ]);

分別在 1000ms2000ms 後產生 promise。

使用 Promise.race() 從兩個 promise 中選擇 最先產生 的 promise。

race000

timeout()

let resolveAfter = ms => val => new Promise(resolve => setTimeout(() => resolve(val), ms));

let timeout = ms => ps => {
  let timeoutID;

  let timeoutPromise = new Promise((_, reject) => {
    timeoutID = setTimeout(() => {
      reject(new Error(`Timeout after ${ms} ms`))
    }, ms);
  });

  return Promise.race([ ps, timeoutPromise ])
                .finally(() => clearTimeout(timeoutID));
};

let promise0 = resolveAfter(1000)('Sam');

timeout(500)(promise0)
  .then(console.log)
  .catch(console.error);

第 3 行

let timeout = ms => ps => {
  let timeoutID;

  let timeoutPromise = new Promise((_, reject) => {
    timeoutID = setTimeout(() => {
      reject(new Error(`Timeout after ${ms} ms`))
    }, ms);
  });

  return Promise.race([ ps, timeoutPromise ])
                .finally(() => clearTimeout(timeoutID));
};

timeout() 可建立一個 timeout promise,並與傳入的 promise 透過 Promise.race() 比較:

  • 若傳入 fulfilled promise 比 timeout promise 快,則回傳 fulfilled promise
  • 若傳入 fulfilled promise 比 timeut promise 快,則回傳 rejected promise

race001

Wink-fp

import { resolveAfter, timeout } from 'wink-fp';
 
let promise0 = resolveAfter(1000)('Sam');

timeout(500)(promise0)
  .then(console.log)
  .catch(console.error);

Wink-fp 已經內建 resolveAfter()timeout(),可直接使用。

timeout()
Number -> Promise a -> Promise a | Promise b
若大於指定時間,則回傳 rejected promise,否則傳回 fulfilled promise

Number:timeout 時間,為 ms

Promise a:data 為欲比較的 promise

Promise a | Promise b:回傳為原 promise,或者 timeout 的 rejected promise

timeout002

Conclusion

  • Timeout promise 為常見的需求,透過 Wink-fp 的 timeout() 可簡單建立 timeout promise

Reference

Marius Schulz, Wait for the Fastest JavaScript Promise to Settle with Promise.race()
MDN, Promise.race()