promise-unmap
v0.2.5
Published
Await until all promises resolve and reject
Downloads
8
Readme
promiseUnmap
Similar to Promise.map(ary) with some connotations:
If all promises resolve, the global promise resolves, that is identical.
All promises are going to be started, unmap won't
fulfill until all of them resolve or reject.
If any promises reject, promiseUnmap will reject with an Error containing all errors in its body as
err.errors: Array<Error>
. The message of the global error will be: "One or more tasks failed". Any fulfillments will also be insideerr.fulfillments: Array<any>
If it fulfills, it will resolve the map of fulfillments.
Usage
Either const {promiseUnmap} = require('promise-unmap')
or import {promiseUnmap} from 'promise-unmap'
It accepts an array of promises or functions that return promises.
const {promiseUnmap} = require('../')
// ...
const ops = [
async () => 'resolves 1',
async () => { throw new Error('fails 2') },
Promise.resolve('resolves 3'),
async () => 'resolves 4',
Promise.reject(new Error('fails 5')),
async () => 'resolves 6',
]
promiseUnmap(ops)
.catch(err => {
expect(err.errors.length).to.equal(2)
expect(err.fulfillments.length).to.equal(4)
})
})
promiseUnmapSerial
Chain calls, return all results, throw if any errors.
it('should fail with mixed requests in serial', function(done) {
promiseUnmapSerial(ops)
.catch(err => {
expect(err.errors.length).to.equal(2)
expect(err.fulfillments.length).to.equal(4)
done()
})
})
t('should not fail if all are passing in serial', function(done) {
promiseUnmapSerial(passingOps)
.then(results => {
expect(results.length).to.equal(2)
done()
})
.catch(done)
})
Implementation
It is pretty obscure, read with caution. Basically consists on wrapping all promises with a safe catch, to later processing the results.
It is written in typescript. A type Future
is defined as a promise
or an async function (something that returns a promise). This way
we can warrantee that promises are not started until they are called.
type Future = Promise | () => Promise
A typeof
check is performed to know whether the future should
begin or it is an unfulfilled promise that we must await.
export function promiseUnmap (futures: Array<Future>) {
return Promise.all(futures.map(f => {
return typeof f === 'function'
? f().catch((err: Error) => err)
: f.catch((err: Error) => err)
})).then((results: Array<any>) => {
if (results.some(r => r instanceof Error)) {
throw new PromiseUnmapError(results)
}
return results
})
}
The following method, promiseUnmapSerial
has been defined to enqueue such futures,
to safely execute a number of asynchronous functions, without interfering one another
(or await serially for promises to finish, but for that we already have
bluebird's mapSeries
)
export function promiseUnmapSerial (futures: Array<Future>) {
const safePromises = futures.map(f => {
const p = typeof f === 'function' ? f() : f
return p.catch(err => err)
})
return safePromises.reduce((accPromises, currPromise) =>
accPromises.then(accResults =>
currPromise.then(currResult => [...accResults, currResult])
)
, Promise.resolve([]))
.then(results => {
if (results.some((r: any) => r instanceof Error)) {
return Promise.reject(new PromiseUnmapError(results))
}
return results
})
}