由於 Promise 是 Asynchronous,因此回傳時間不確定,若想實作出超過指定時間就 Timeout,可使用 Promise.race() 實作。
Version
macOS Mojave 10.14.6
VS Code 1.38.1
Quokka 1.0.253
ECMAScript 2015
Promise.race()
import { resolveAfter, log } from 'wink-fp'
let data = [
resolveAfter(1000)(1),
resolveAfter(2000)(2),
resolveAfter(3000)(3),
]
Promise.race(data)
.then(log)
.catch(log)
第 3 行
let data = [
resolveAfter(1000)(1),
resolveAfter(2000)(2),
resolveAfter(3000)(3),
]
data 內有 3 個 promise,依次在 1 秒、2 秒、3 秒後產生。
第 9 行
Promise.race(data)
.then(log)
使用 Promise.race() 從兩個 promise 中選擇 最先產生 的 promise。
無論是 fulfilled project 或 rejected promise,只要是最先 settled promise 即可

Timeout Promise
import { resolveAfter, log, rejectAfter, error } from 'wink-fp'
let data = resolveAfter(1000)(1)
let timeout = rejectAfter(500)(new Error('Timeout after 500 ms'))
Promise.race([data, timeout])
.then(log)
.catch(error)
若想要實作非同步只等待一段時間,超過時間就 timeout 放棄,可另外建立一個 rejected promise 由 Promise.race() 決定。

Timeout Promise
import { resolveAfter, log, error } from 'wink-fp'
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)(1);
timeout(500)(promise0)
.then(log)
.catch(error);
亦可以相同原理實作出 timeout()。
第 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

Conclusion
Promise.race()一般不常使用,但透過Promise.race()與自行建立的 timeout rejected promise 比較,可實作出若超過時間 timeout 就放棄 promise 的需求
Reference
Marius Schulz, Wait for the Fastest JavaScript Promise to Settle with Promise.race()
MDN, Promise.race()