Created
June 22, 2021 13:11
-
-
Save teidesu/d2ebd40aaf3e7aff2a041871081a2c0b to your computer and use it in GitHub Desktop.
Promise.race but error-tolerant
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Similar to Promise.race(), but resolves once one of the promises | |
* resolve to a successful value and didn't throw error. | |
* A promise result is considered `successful` when | |
* check(result) resolves to a truthy value. | |
* | |
* When all promises resulted with unsuccessful values, `null` is returned, | |
* otherwise result of first successful one is returned | |
* | |
* @param proms List of promises | |
* @param checker (optional) Function which is used to determine whether value is successful | |
* @param errorHandler (optional) Function which will be called each time one of promises throws an error | |
*/ | |
function successRace (proms, checker = e => !!e, errorHandler = null) { | |
return new Promise((resolve) => { | |
Promise.all(proms.map((prom) => | |
prom.then((res) => { | |
if (checker(res)) resolve(res) | |
}).catch(errorHandler || (() => {})) | |
)).then(() => resolve(null)) | |
}) | |
} | |
async function test () { | |
const sleep = ms => new Promise((resolve) => setTimeout(resolve, ms)) | |
function falsy () { | |
return Promise.resolve({ | |
ok: false | |
}) | |
} | |
function falsyErr () { | |
return Promise.reject(Error('error')) | |
} | |
function falsyErrDelayed () { | |
return sleep(100).then(() => { | |
throw Error('error') | |
}) | |
} | |
function falsyDelayed () { | |
return sleep(100).then(() => ({ | |
ok: false | |
})) | |
} | |
function truthy () { | |
return sleep(150).then(() => ({ | |
ok: true, | |
value: 'truthy()' | |
})) | |
} | |
function truthyDelayed () { | |
return sleep(200).then(() => ({ | |
ok: true, | |
value: 'truthyDelayed()' | |
})) | |
} | |
const eql = (a, b) => { | |
if (a !== b) throw new Error(`Expected ${a} to equal ${b}`) | |
} | |
let res | |
res = await successRace([], i => i.ok) | |
eql(res, null) | |
res = await successRace([falsy(), truthy()], i => i.ok) | |
eql(res.value, 'truthy()') | |
res = await successRace([falsy(), falsyDelayed(), truthyDelayed()], i => i.ok) | |
eql(res.value, 'truthyDelayed()') | |
res = await successRace([falsy(), falsyDelayed(), truthy(), truthyDelayed()], i => i.ok) | |
eql(res.value, 'truthy()') | |
res = await successRace([falsy(), falsyDelayed(), falsyDelayed()], i => i.ok) | |
eql(res, null) | |
let errCalled = false | |
let errHandler = () => errCalled = true | |
res = await successRace([falsyErr(), truthyDelayed()], i => i.ok, errHandler) | |
eql(res.value, 'truthyDelayed()') | |
eql(errCalled, true) | |
errCalled = false | |
res = await successRace([falsyErr(), falsyErrDelayed(), truthyDelayed()], i => i.ok, errHandler) | |
eql(res.value, 'truthyDelayed()') | |
eql(errCalled, true) | |
console.log('tests ok!') | |
} | |
test().catch(console.error) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment