UNPKG

modern-async

Version:

A modern tooling library for asynchronous operations using async/await, promises and async generators

63 lines (59 loc) 2.35 kB
import assert from 'nanoassert' import asyncWrap from './asyncWrap.mjs' /** * Performs a reduce operation as defined in the `Array.reduce()` method but using an asynchronous * function as reducer. The reducer will be called sequentially. * * @param {Iterable | AsyncIterable} iterable An iterable or async iterable object. * @param {Function} reducer The reducer function. It will be called with four arguments: * * `accumulator`: The last calculated value (or the first value of the iterable if no initial value is provided) * * `value`: The current value * * `index`: The current index in the iterable. Will start from 0 if no initial value is provided, 1 otherwise. * * `iterable`: The iterable on which the reduce operation is performed. * @param {any} [initial] The initial value that will be used as accumulator in the first call to * `reducer`. If omitted the first element of `iterable` will be used as accumulator and `reducer` * will only be called from from the second element of the list (as defined in the `Array.reduce()` * function). * @returns {Promise} A promise that will be resolved with the result of the reduce operation, * or rejected if any of the calls to `reducer` throws an exception. * @example * import { asyncReduce, asyncSleep } from 'modern-async' * * const array = [1, 2, 3] * const result = await asyncReduce(array, async (v, p) => { * // these calls will be performed sequentially * await asyncSleep(10) // waits 10ms * return v + p * }) * console.log(result) // prints 6 * // total processing time should be ~ 20ms */ async function asyncReduce (iterable, reducer, initial = undefined) { assert(typeof reducer === 'function', 'iteratee must be a function') reducer = asyncWrap(reducer) if (initial !== undefined) { let current = initial let i = 0 for await (const el of iterable) { current = await reducer(current, el, i, iterable) i += 1 } return current } else { let i = 0 let current for await (const el of iterable) { if (i === 0) { current = el } else { current = await reducer(current, el, i, iterable) } i += 1 } if (i === 0) { throw new TypeError('Reduce of empty array with no initial value') } return current } } export default asyncReduce