reduce.js

import {asAsyncIterator, syncType} from './lib/get_iterator'

/**
```
import {reduce} from 'async_iter/pipeline/reduce' # pipeline version
import {reduce} from 'async_iter/reduce' # conventional version
```
 * Apply reducer function to each item of the source iterable, returning the single reduce value
> Supports both **sync** and  **async** iterations.  Always returns an **async** iterator

 * @param  {Iterable}         source        The source iteration to rate limit
 * @param  {reducerCallback}  fn            The function to call for each item
 * @param  {*}                initialValue  The initial value to supply to the first call of fn
 * @return {*} The final reduced value
 * @function
 * @name reduce
 * @memberof module:Operators
 */

export const reduce = syncType(syncReduce, asyncReduce)

function syncReduce(source, fn, initialValue) {
  let index = 0
  let accumulator = initialValue
  for (const item of source)
    accumulator = fn(accumulator, item, index++)
  return accumulator
}

async function asyncReduce(source, fn, initialValue) {
  source = await asAsyncIterator(source)

  let index = 0
  let accumulator = initialValue
  for await (const item of source)
    accumulator = await fn(accumulator, item, index++)
  return accumulator
}