I have a requirement to run Promise.any in series.
As it's not available (Am I right?) I wrote a function to execute promises in series (with help of Pomise.mapSeries) and resolves at first test satisfied.
The approach is:
Here is the code:
const Promise = require('bluebird')
let delay = 1000
const BIG = 10
function isBig (n) {
return Promise.delay(delay).then(() => {
console.log('[test] n: ', n)
if (n < 0) return Promise.reject(new Error('Negative number'))
else if (n > BIG) return Promise.resolve(n)
else return Promise.resolve(false)
})
delay -= 100 // just to check array items are executing in series
}
function anySeries (arr, test) {
return Promise.mapSeries(arr, n => {
return isBig(n)
.then(res => {
if (res) {
let err = new Error('Stop As Found')
err.result = n
return Promise.reject(err)
} else {
return res
}
})
})
.then(res => {
console.log('[AS] each output: ' + JSON.stringify(res))
return null
}).catch(err => {
console.log('[AS] Let me check error')
if (/^Stop As Found$/.test(err.message)) {
console.log('[AS] Found the desired')
console.log('[AS] Final result: ', err.result)
return Promise.resolve(err.result)
} else {
console.error('[AS] Internal error')
console.error('[AS] Returing error: ', err.message)
return Promise.reject(err)
}
})
}
let arr = [ 1, 11, 5, -1, 13, 15]
// find bigger than 10
console.log('---Test 1 (will find)---')
anySeries(arr, isBig)
.then(res => {
console.log('Arr: %s, Big one: %s', arr, res)
arr = [ 1, 3, 5]
console.log('\n---Test 2 (will not find)---')
return anySeries(arr, isBig)
})
.then(res => {
console.log('Arr: %s, Big one: %s', arr, res)
arr = [ 1, 2, -1, 13, 15, 2]
console.log('\n---Test 3 (wiil result in error)---')
return anySeries(arr, isBig)
})
.catch(console.error)
If there is better approach I would like to know, preferably with Promise.
A simpler way to do this is to simply loop over your input values and await
the promise.
arr
isBig
if (res)
, don't continue processing the rest of the arrayasync function series(values, map, check) {
for (let i = 0; i < values.length; i++) {
const res = await map(values[i], i, values);
if (check(res, i, values)) {
return res;
}
}
// This might be desirable or it might not. Up to you.
throw new Error('No result');
}
series(arr, isBig, (res) => !!res)
.then((result) => {
// A value was resolved to.
console.log('[AS] Found the desired');
console.log('[AS] Final result: ', result);
})
.catch((err) => {
console.error('[AS] Internal error');
console.error('[AS] Returning error: ', err.message);
});
If you want to make processing the array 'fault tolerant' by ignoring any errors you can add a try { ... } catch {}
inside the for
loop. If you want to have a default value that series
resolves to, add a return ...;
at the end of the async function
rather than throw
.