Skip to content

Instantly share code, notes, and snippets.

@mLuby
Last active January 19, 2017 20:39
Show Gist options
  • Save mLuby/2b7084d15649e54496340539d7bc0c45 to your computer and use it in GitHub Desktop.
Save mLuby/2b7084d15649e54496340539d7bc0c45 to your computer and use it in GitHub Desktop.
Race all promises once and resolve with the first resolved promise or reject with the last error. Useful for connecting.
"use strict"
// race all promises once and resolve with the first resolved promise or reject with the last error.
function raceWithTimeout (promiseList) {
const TIMEOUT = 50
return Promise.race([
...promiseList.map(suppressReject), // if any resolve, resolve with that result.
lastRejectionWithTimeout(promiseList, TIMEOUT) // if all reject, reject with last error; if timeout, reject with latest error.
])
}
function lastRejectionWithTimeout(promiseList, timeoutMs) {
return new Promise((_, reject) => {
let numEndedPromises = 0
let lastError = null
setTimeout(() => reject(Object.assign(lastError, {message: `Timed out. Latest error: ${lastError.message}`})), timeoutMs)
promiseList.forEach(promise => promise
.then(rejectLastIfPromisesDone)
.catch(error => {
lastError = error
rejectLastIfPromisesDone()
})
)
function rejectLastIfPromisesDone () {
numEndedPromises = numEndedPromises + 1
if (numEndedPromises === promiseList.length && lastError) {
reject(lastError)
}
}
})
}
function suppressReject (promise) {
return new Promise(resolve => promise.then(resolve))
}
raceWithTimeout([
new Promise((resolve, reject) => {setTimeout(() => reject(new Error("bad config")), 10)}),
new Promise((resolve, reject) => {setTimeout(() => reject(new Error("wrong password")), 0)}),
]).then(result => console.log("X", result)).catch(error => console.error(error.message === "bad config" ? "√" : "X", error))
raceWithTimeout([
new Promise((resolve, reject) => {setTimeout(() => reject(new Error("bad config")), 10)}),
new Promise((resolve, reject) => {setTimeout(() => resolve("connection"), 20)}),
new Promise((resolve, reject) => {setTimeout(() => reject(new Error("wrong password")), 0)}),
]).then(result => console.log("√", result)).catch(error => console.error("X", error))
raceWithTimeout([
new Promise((resolve, reject) => {setTimeout(() => reject(new Error("bad config")), 30)}),
new Promise((resolve, reject) => {setTimeout(() => reject(new Error("wrong password")), 40)}),
// timeout at 50
new Promise((resolve, reject) => {setTimeout(() => resolve("connection"), 60)}),
new Promise((resolve, reject) => {setTimeout(() => reject(new Error("unknown server")), 70)}),
]).then(result => console.log("√", result)).catch(error => console.error(error.message === "Timed out. Latest error: wrong password" ? "√" : "X", error))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment