UNPKG

async-collection-utils

Version:

A well tested and typed collection of map, forEach, reduce, filter etc. utility functions supporting arrays, sets, maps, plain objects, iterators in both async and synchronous versions.

294 lines (236 loc) 12 kB
# Async Utility Functions A well tested and typed collection of map, forEach, reduce, filter etc. utility functions supporting arrays, sets, maps, plain objects, iterators in both async and synchronous versions. * [Core Concepts](#core-concepts) * [Usage](#usage) * [Import](#import) * [Array Utilities](#array-utilities) * [Sequential](#sequential) * [Parallel](#parallel) * [Object Utilities](#object-utilities) * [Sequential](#sequential-1) * [Parallel](#parallel-1) * [Using Break and Last](#using-break-and-last) * [Synchronous](#synchronous) * [Helpers](#helpers) * [Changelog](#changelog) ## Core Concepts Each method (except for "forEach" and all "toArray" utilities) returns the same type as the input: asyncMap(new Map(), () => {}) returns Promise<Map> etc. - **Break**: A symbol that can be returned to stop the iteration. - **Last**: A utility that wraps a value. When returned, it stops the iteration and the provided value becomes the final output. ## Usage ### Basic ```javascript import { asyncMap, map, asyncReduce, Break, Last } from 'async-collection-utils'; const data = [1, 2, 3]; const result = await asyncMap(data, async (item) => Promise.resolve(item * 2)); // result: [2, 4, 6] const data = new Set([1, 2, 3]); const result = await asyncMap(data, async (item) => Promise.resolve(item + 1)); // result: Set { 2, 3, 4 } const data = { a: 1, b: 2, c: 3 }; const result = map(data, async (value, key) => value + key); // result: { a: '1a', b: '2b', c: '3c' } const cursor = model.find({}).cursor(); const result = await asyncReduce(cursor, async (acc, item) => Promise.resolve(acc + item.value), 0); // result: number ``` ### Utilities table Each type of utility has both async and sync versions. These return the same type as the input. The "toArray" utilities accept the same input but always return an array. | | map | flatMap | filter | reduce | forEach | |:--------------|:---:|:-------:|:------:|:------:|:-------:| | async | | | | | | | sync | | | | | | | toArray async | | | | n/a | n/a | | toArray sync | | | | n/a | n/a | ### Input/output support map | | Array<T> | Set<T> | Map<K, T> | Record<K, T> | TypedArray<T> | Iterable<T> | AsyncIterable<T> | |---------------------------------------|-------------------|-------------------|--------------------|-----------------------|------------------------|----------------------------|----------------------------| | asyncMap<TInput, R> | Promise<Array<R>> | Promise<Set<R>> | Promise<Map<K, R>> | Promise<Record<K, R>> | Promise<TypedArray<R>> | Promise<AsyncGenerator<R>> | Promise<AsyncGenerator<R>> | | map<TInput, R> | Array<R> | Set<R> | Map<K, R> | Record<K, R> | TypedArray<R> | Generator<R> | | | asyncMapToArray<TInput, R> | Promise<Array<R>> | Promise<Array<R>> | Promise<Array<R>> | Promise<Array<R>> | Promise<Array<R>> | Promise<Array<R>> | Promise<Array<R>> | | mapToArray<TInput, R> | Array<R> | Array<R> | Array<R> | Array<R> | Array<R> | Array<R> | | | asyncFlatMap<TInput, R \| R[]> | Promise<Array<R>> | Promise<Set<R>> | | | Promise<TypedArray<R>> | Promise<AsyncGenerator<R>> | Promise<AsyncGenerator<R>> | | flatMap<TInput, R \| R[]> | Array<R> | Set<R> | | | TypedArray<R> | Generator<R> | | | asyncFlatMapToArray<TInput, R \| R[]> | Promise<Array<R>> | Promise<Array<R>> | Promise<Array<R>> | Promise<Array<R>> | Promise<Array<R>> | Promise<Array<R>> | Promise<Array<R>> | | flatMapToArray<TInput, R \| R[]> | Array<R> | Array<R> | Array<R> | Array<R> | Array<R> | Array<R> | | | asyncFilter<TInput, boolean> | Promise<Array<R>> | Promise<Set<R>> | Promise<Map<K, R>> | Promise<Record<K, R>> | Promise<TypedArray<R>> | Promise<AsyncGenerator<R>> | Promise<AsyncGenerator<R>> | | filter<TInput, boolean> | Array<R> | Set<R> | Map<K, R> | Record<K, R> | TypedArray<R> | Generator<R> | | | asyncFilterToArray<TInput, boolean> | Promise<Array<R>> | Promise<Array<R>> | Promise<Array<R>> | Promise<Array<R>> | Promise<Array<R>> | Promise<Array<R>> | Promise<Array<R>> | | filterToArray<TInput, boolean> | Array<R> | Array<R> | Array<R> | Array<R> | Array<R> | Array<R> | | | asyncReduce<TInput, R> | Promise<R> | Promise<R> | Promise<R> | Promise<R> | Promise<R> | Promise<R> | Promise<R> | | reduce<TInput, R> | R | R | R | R | R | R | | | asyncForEach<TInput, void> | void | void | void | void | void | void | void | | forEach<TInput, void> | void | void | void | void | void | void | | ### Usage with iterables All functions accept iterables () ### Map functions #### map ```javascript import { map } from 'async-collection-utils'; const results = map([1, 2, 3], (item) => item * 2); // results: [2, 4, 6] const results = map(new Set([1, 2, 3]), (item) => item * 2); // results: Set { 2, 4, 6 } const results = map({ a: 1, b: 2, c: 3 }, (value, key) => value + key); // results: { a: '1a', b: '2b', c: '3c' } const results = map(new Map([['a', 1], ['b', 2], ['c', 3]]), (value, key) => value + key); // results: Map { a: '1a', b: '2b', c: '3c' } const results = map(model.find({}).cursor(), (item) => parseInt(item.value)); // results: Generator<number> const generator = function* () { yield 1; yield 2; yield 3; }; const results = map(generator(), async (item) => item * 2); // results: Generator<number> ``` #### asyncMap ```javascript import { asyncMap } from 'async-collection-utils'; const results = await asyncMap([1, 2, 3], async (item) => Promise.resolve(item * 2)); // results: [2, 4, 6] const results = await asyncMap(new Set([1, 2, 3]), async (item) => Promise.resolve(item * 2)); // results: Set { 2, 4, 6 } const results = await asyncMap({ a: 1, b: 2, c: 3 }, async (value, key) => Promise.resolve(value + key)); // results: { a: '1a', b: '2b', c: '3c' } const results = await asyncMap(new Map([['a', 1], ['b', 2], ['c', 3]]), async (value, key) => Promise.resolve(value + key)); // results: Map { a: '1a', b: '2b', c: '3c' } const results = await asyncMap(model.find({}).cursor(), async (item) => Promise.resolve(parseInt(item.value))); // results: AsyncGenerator<number> const asyncGenerator = function* () { yield 1; yield 2; yield 3; }; const results = await asyncMap(generator(), async (item) => Promise.resolve(item * 2)); // results: AsyncGenerator<number> const generator = function* () { yield 1; yield 2; yield 3; }; const results = await asyncMap(generator(), async (item) => Promise.resolve(item * 2)); // results: AsyncGenerator<number> ``` #### mapToArray ```javascript import { mapToArray } from 'async-collection-utils'; const results = mapToArray([1, 2, 3], (item) => item * 2); // results: [2, 4, 6] const results = mapToArray(new Set([1, 2, 3]), (item) => item * 2); // results: [2, 4, 6] const results = mapToArray({ a: 1, b: 2, c: 3 }, (value, key) => value + key); // results: ['1a', '2b', '3c'] const results = mapToArray(new Map([['a', 1], ['b', 2], ['c', 3]]), (value, key) => value + key); // results: ['1a', '2b', '3c'] const results = mapToArray(model.find({}).cursor(), (item) => parseInt(item.value)); // results: number[] const generator = function* () { yield 1; yield 2; yield 3; }; const results = mapToArray(generator(), async (item) => item * 2); // results: [2, 4, 6] ``` ### Using Break and Last You can use `Break` to finish the iteration early in all functions. ```javascript const data = [1, 2, 3, 4, 5]; const result = await asyncFlatMap(data, async (item) => { if (item === 3) return Break; return item * 2; }); // result: [2, 4] ``` ```javascript const data = { a: 1, b: 2, c: 3, d: 4, e: 5 }; const result = await asyncMap(data, async (value) => { if (value === 3) return Break; return value * 2; }); // result: { a: 2, b: 4 } ``` You can use `Last` wrapper, to finish the iteration early while still returning last value. It works in all `map`, `flatMap`, `reduce` and `filter` functions. ```javascript const data = [1, 2, 3, 4, 5]; const result = await asyncFlatMap(data, async (item) => { if (item === 3) return Last(item * 2); return item * 2; }); // result: [2, 4, 6] ``` ```javascript const data = [1, 2, 3, 4, 5]; const reduced = await asyncReduce(data, async (acc, item) => { if (item === 3) return Last(acc + item); return acc + item; }, 0); // result: 6 ``` ### Helpers Two helpers used internally are exported as well: - `entries`: The same as `Object.entries` but with better typings ```javascript import { entries } from 'async-collection-utils'; enum SomeEnum { foo = 'foo', bar = 'bar', } const obj = { [SomeEnum.foo]: 1, [SomeEnum.bar]: 2 }; const result: [SomeEnum, number][] = await entries(obj); // result: [[SomeEnum.foo, 1], [SomeEnum.bar, 2]] ``` - `keys`: The same as `Object.keys` but with better typings ```javascript import { keys } from 'async-collection-utils'; enum SomeEnum { foo = 'foo', bar = 'bar', } const obj = { [SomeEnum.foo]: 1, [SomeEnum.bar]: 2 }; const result: SomeEnum[] = await keys(obj); // result: [SomeEnum.foo, SomeEnum.bar] ``` ## Array-like objects Methods are not generic meaning that they won't treat array-like objects as arrays. They will be iterated over just like plain objects. ```javascript import { map } from 'async-collection-utils'; const obj = { 0: 'a', 1: 'b', length: 2 }; const result = map(obj, (value, key) => value + key); // result: { 0: 'a0', 1: 'b1', length: '2length' } ``` ## Notes - Remember to always pass async iteratee to async functions; otherwise, type inference will fail ## Changelog ### 1.0.0 - Initial release ### 1.1.0 - Added synchronous utilities - Added `entries` and `keys` helpers ### 2.0.0 - BREAKING CHANGE: complete rewrite of the library - All async utilities accept: arrays, sets, maps, typed arrays, iterators, async iterators and plain objects and return the same type as the input - All async utilities have sync counterparts - All sync utilities accept: arrays, sets, maps, typed arrays, iterators, and plain objects and return the same type as the input - Utilities available: - asyncMap - map - asyncMapToArray - mapToArray - asyncFlatMap - flatMap - asyncFlatMapToArray - flatMapToArray - asyncFilter - filter - asyncFilterToArray - filterToArray - asyncReduce - reduce - asyncForEach - forEach - batch - entries - keys