Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/metarhia/metasync

Asynchronous Programming Library for JavaScript & Node.js
https://github.com/metarhia/metasync

array async asynchronous callback chain collector composition impress javascript js metarhia node nodejs parallel promise series sync synchronous thenable

Last synced: 5 days ago
JSON representation

Asynchronous Programming Library for JavaScript & Node.js

Awesome Lists containing this project

README

        

# Asynchronous Programming Library

[![ci status](https://github.com/metarhia/metasync/workflows/Testing%20CI/badge.svg)](https://github.com/metarhia/metasync/actions?query=workflow%3A%22Testing+CI%22+branch%3Amaster)
[![snyk](https://snyk.io/test/github/metarhia/metasync/badge.svg)](https://snyk.io/test/github/metarhia/metasync)
[![npm version](https://badge.fury.io/js/metasync.svg)](https://badge.fury.io/js/metasync)
[![npm downloads/month](https://img.shields.io/npm/dm/metasync.svg)](https://www.npmjs.com/package/metasync)
[![npm downloads](https://img.shields.io/npm/dt/metasync.svg)](https://www.npmjs.com/package/metasync)
[![license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/metarhia/metasync/blob/master/LICENSE)

## Installation

```bash
$ npm install metasync
```

## Asynchronous functions composition

`metasync(fns)(data, done)`

- `fns` - array of callback-last functions, callback contranct err-first
- `data` - input data (optional)
- `done` - err-first callback
- Returns: composed callback-last / err-first function

![composition](https://cloud.githubusercontent.com/assets/4405297/16968374/1b81f160-4e17-11e6-96fa-9d7e2b422396.png)

```js
const composed = metasync([f1, f2, f3, [[f4, f5, [f6, f7], f8]], f9]);
```

- Array of functions gives sequential execution: `[f1, f2, f3]`
- Double brackets array of functions gives parallel execution: `[[f1, f2, f3]]`

_Example:_

```js
const metasync = require('metasync');
const fs = require('fs');

// Data collector (collect keys by count)
const dc = metasync.collect(4);

dc.pick('user', { name: 'Marcus Aurelius' });
fs.readFile('HISTORY.md', (err, data) => dc.collect('history', err, data));
dc.take('readme', fs.readFile, 'README.md');
setTimeout(() => dc.pick('timer', { date: new Date() }), 1000);

// Key collector (collect certain keys by names)
const kc = metasync
.collect(['user', 'history', 'readme', 'timer'])
.timeout(2000)
.distinct()
.done((err, data) => console.log(data));

kc.pick('user', { name: 'Marcus Aurelius' });
kc.take('history', fs.readFile, 'HISTORY.md');
kc.take('readme', fs.readFile, 'README.md');
setTimeout(() => kc.pick('timer', { date: new Date() }), 1000);
```

## API

### callbackify(fn)

- `fn`: [``][function] promise-returning function

_Returns:_ [``][function]

Convert Promise-returning to callback-last / error-first contract

### asyncify(fn)

- `fn`: [``][function] regular synchronous function

_Returns:_ [``][function] with contract: callback-last / error-first

Convert sync function to callback-last / error-first contract

### promiseToCallbackLast(promise, callback)

- `promise`: [``][promise]
- `callback`: [``][function]

Convert Promise to callback-last

### promisify(fn)

- `fn`: [``][function] callback-last function

_Returns:_ [``][function] Promise-returning function

Convert async function to Promise-returning function

### promisifySync(fn)

- `fn`: [``][function] regular synchronous function

_Returns:_ [``][function] Promise-returning function

Convert sync function to Promise object

### map(items, fn, done)

- `items`: [``][array] incoming
- `fn`: [``][function] to be executed for each value in the array
- `current`: `` current element being processed in the array
- `callback`: [``][function]
- `err`: [``][error]|[``][null]
- `value`: ``
- `done`: [``][function] on done
- `err`: [``][error]|[``][null]
- `result`: [``][array]

Asynchronous map (iterate parallel)

### filter(items, fn, done)

- `items`: [``][array] incoming
- `fn`: [``][function] to be executed for each value in the array
- `value`: `` item from items array
- `callback`: [``][function]
- `err`: [``][error]|[``][null]
- `accepted`: [``][boolean]
- `done`: [``][function] on done
- `err`: [``][error]|[``][null]
- `result`: [``][array]

Asynchrous filter (iterate parallel)

_Example:_

```js
metasync.filter(
['data', 'to', 'filter'],
(item, callback) => callback(item.length > 2),
(err, result) => console.dir(result),
);
```

### reduce(items, fn, done\[, initial\])

- `items`: [``][array] incoming
- `fn`: [``][function] to be executed for each value in array
- `previous`: `` value previously returned in the last iteration
- `current`: `` current element being processed in the array
- `callback`: [``][function] callback for returning value back to
reduce function
- `err`: [``][error]|[``][null]
- `data`: `` resulting value
- `counter`: [``][number] index of the current element being processed
in array
- `items`: [``][array] the array reduce was called upon
- `done`: [``][function] on done
- `err`: [``][error]|[``][null]
- `result`: [``][array]
- `initial`: `` optional value to be used as first argument in first
iteration

Asynchronous reduce

### reduceRight(items, fn, done\[, initial\])

- `items`: [``][array] incoming
- `fn`: [``][function] to be executed for each value in array
- `previous`: `` value previously returned in the last iteration
- `current`: `` current element being processed in the array
- `callback`: [``][function] callback for returning value back to
reduce function
- `err`: [``][error]|[``][null]
- `data`: `` resulting value
- `counter`: [``][number] index of the current element being processed
in array
- `items`: [``][array] the array reduce was called upon
- `done`: [``][function] on done
- `err`: [``][error]|[``][null]
- `result`: [``][array]
- `initial`: `` optional value to be used as first argument in first
iteration

Asynchronous reduceRight

### each(items, fn, done)

- `items`: [``][array] incoming
- `fn`: [``][function]
- `value`: `` item from items array
- `callback`: [``][function]
- `err`: [``][error]|[``][null]
- `done`: [``][function] on done
- `err`: [``][error]|[``][null]
- `items`: [``][array]

Asynchronous each (iterate in parallel)

_Example:_

```js
metasync.each(
['a', 'b', 'c'],
(item, callback) => {
console.dir({ each: item });
callback();
},
(err, data) => console.dir('each done'),
);
```

### series(items, fn, done)

- `items`: [``][array] incoming
- `fn`: [``][function]
- `value`: `` item from items array
- `callback`: [``][function]
- `err`: [``][error]|[``][null]
- `done`: [``][function] on done
- `err`: [``][error]|[``][null]
- `items`: [``][array]

Asynchronous series

_Example:_

```js
metasync.series(
['a', 'b', 'c'],
(item, callback) => {
console.dir({ series: item });
callback();
},
(err, data) => {
console.dir('series done');
},
);
```

### find(items, fn, done)

- `items`: [``][array] incoming
- `fn`: [``][function]
- `value`: `` item from items array
- `callback`: [``][function]
- `err`: [``][error]|[``][null]
- `accepted`: [``][boolean]
- `done`: [``][function] on done
- `err`: [``][error]|[``][null]
- `result`: ``

Asynchronous find (iterate in series)

_Example:_

```js
metasync.find(
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
(item, callback) => callback(null, item % 3 === 0 && item % 5 === 0),
(err, result) => {
console.dir(result);
},
);
```

### every(items, fn, done)

- `items`: [``][array] incoming
- `fn`: [``][function]
- `value`: `` item from items array
- `callback`: [``][function]
- `err`: [``][error]|[``][null]
- `accepted`: [``][boolean]
- `done`: [``][function] on done
- `err`: [``][error]|[``][null]
- `result`: [``][boolean]

Asynchronous every

### some(items, fn, done)

- `items`: [``][array] incoming
- `fn`: [``][function]
- `value`: `` item from items array
- `callback`: [``][function]
- `err`: [``][error]|[``][null]
- `accepted`: [``][boolean]
- `done`: [``][function] on done
- `err`: [``][error]|[``][null]
- `result`: [``][boolean]

Asynchronous some (iterate in series)

### asyncMap(items, fn\[, options\]\[, done\])

- `items`: [``][array] incoming dataset
- `fn`: [``][function]
- `item`: ``
- `index`: [``][number]
- `options`: [``][object] map params, optional
- `min`: [``][number] min number of items in one next call
- `percent`: [``][number] ratio of map time to all time
- `done`: [``][function] call on done, optional
- `err`: [``][error]|[``][null]
- `result`: [``][array]

Non-blocking synchronous map

### asyncIter(base)

- `base`: [``][iterable]|[``][asynciterable] an
iterable that is wrapped in [``][asynciterator]

_Returns:_ [``][asynciterator]

Create an AsyncIterator instance

### class AsyncIterator

#### AsyncIterator.prototype.constructor(base)

#### async AsyncIterator.prototype.next()

#### async AsyncIterator.prototype.count()

#### async AsyncIterator.prototype.each(fn, thisArg)

#### async AsyncIterator.prototype.forEach(fn, thisArg)

#### async AsyncIterator.prototype.parallel(fn, thisArg)

#### async AsyncIterator.prototype.every(predicate, thisArg)

#### async AsyncIterator.prototype.find(predicate, thisArg)

#### async AsyncIterator.prototype.includes(element)

#### async AsyncIterator.prototype.reduce(reducer, initialValue)

#### async AsyncIterator.prototype.some(predicate, thisArg)

#### async AsyncIterator.prototype.someCount(predicate, count, thisArg)

#### async AsyncIterator.prototype.collectTo(CollectionClass)

#### async AsyncIterator.prototype.collectWith(obj, collector)

#### async AsyncIterator.prototype.join(sep = ', ', prefix = '', suffix = '')

#### async AsyncIterator.prototype.toArray()

#### AsyncIterator.prototype.map(mapper, thisArg)

#### AsyncIterator.prototype.filter(predicate, thisArg)

#### AsyncIterator.prototype.flat(depth = 1)

#### AsyncIterator.prototype.flatMap(mapper, thisArg)

#### AsyncIterator.prototype.zip(...iterators)

#### AsyncIterator.prototype.chain(...iterators)

#### AsyncIterator.prototype.take(amount)

#### AsyncIterator.prototype.takeWhile(predicate, thisArg)

#### AsyncIterator.prototype.skip(amount)

#### AsyncIterator.prototype.throttle(percent, min)

#### AsyncIterator.prototype.enumerate()

### collect(expected)

- `expected`: [``][number]|[``][string]

_Returns:_ [``][collector]

Create Collector instance

### class Collector

Data collector

#### Collector.prototype.constructor(expected)

- `expected`: [``][number]|[``][string] count or keys

Data collector

#### Collector.prototype.collect(key, err, value)

- `key`: [``][string]
- `err`: [``][error]
- `value`: ``

_Returns:_ [``][this]

Pick or fail key

#### Collector.prototype.pick(key, value)

- `key`: [``][string]
- `value`: ``

_Returns:_ [``][this]

Pick key

#### Collector.prototype.fail(key, err)

- `key`: [``][string]
- `err`: [``][error]

_Returns:_ [``][this]

Fail key

#### Collector.prototype.take(key, fn, args)

- `key`: [``][string]
- `fn`: [``][function]
- `args`: [``][array] rest arguments, to be passed in fn

_Returns:_ [``][this]

Take method result

#### Collector.prototype.timeout(msec)

- `msec`: [``][number]

_Returns:_ [``][this]

Set timeout

#### Collector.prototype.done(callback)

- `callback`: [``][function]
- `err`: [``][error]
- `data`: ``

_Returns:_ [``][this]

Set on done listener

#### Collector.prototype.finalize(key, err, data)

#### Collector.prototype.distinct(value)

- `value`: [``][boolean]

_Returns:_ [``][this]

Deny or allow unlisted keys

#### Collector.prototype.cancel(err)

#### Collector.prototype.then(fulfill, reject)

### compose(flow)

- `flow`: [``][function] callback-last / err-first

_Returns:_ [``][function] composed callback-last / err-first

Asynchronous functions composition

Array of functions results in sequential execution: `[f1, f2, f3]` Double
brackets array of functions results in parallel execution: `[[f1, f2, f3]]`

_Example:_

```js
const composed = metasync([f1, f2, f3, [[f4, f5, [f6, f7], f8]], f9]);
```

### class Composition

#### Composition.prototype.constructor()

#### Composition.prototype.on(name, callback)

#### Composition.prototype.finalize(err)

#### Composition.prototype.collect(err, result)

#### Composition.prototype.parallel()

#### Composition.prototype.sequential()

#### Composition.prototype.then(fulfill, reject)

#### Composition.prototype.clone()

Clone composed

#### Composition.prototype.pause()

Pause execution

#### Composition.prototype.resume()

Resume execution

#### Composition.prototype.timeout(msec)

- `msec`: [``][number]

Set timeout

#### Composition.prototype.cancel()

Cancel execution where possible

### firstOf(fns, callback)

- `fns`: [``][function] callback-last / err-first
- `callback`: [``][function] on done, err-first

Executes all asynchronous functions and pass first result to callback

### parallel(fns\[, context\], callback)

- `fns`: [``][function] callback-last / err-first
- `context`: [``][object] incoming data, optional
- `callback`: [``][function] on done, err-first

Parallel execution

_Example:_

```js
metasync.parallel([f1, f2, f3], (err, data) => {});
```

### sequential(fns\[, context\], callback)

- `fns`: [``][function] callback-last with err-first contract
- `context`: [``][object] incoming data, optional
- `callback`: [``][function] err-first on done

Sequential execution

_Example:_

```js
metasync.sequential([f1, f2, f3], (err, data) => {});
```

### runIf(condition\[, defaultVal\], asyncFn, ...args)

- `condition`: ``
- `defaultVal`: `` optional, value that will be returned to callback if
`condition` is falsy.
- `asyncFn`: [``][function] callback-last function that will be
executed if `condition` if truthy
- `args`: `` args to pass to `asyncFn`

Run `asyncFn` if `condition` is truthy, else return `defaultVal` to callback.

### runIfFn(asyncFn, ...args)

- `asyncFn`: [``][function] callback-last function that will be
executed if it is provided
- `args`: `` args to pass to `asyncFn`

Run `asyncFn` if it is provided

### class do

#### do.prototype.constructor(fn, ...args)

### toAsync(fn)

- `fn`: [``][function] callback-last / err-first

_Returns:_ [``][function]

Convert synchronous function to asynchronous

Transform function with args arguments and callback to function with args as
separate values and callback

### asAsync(fn, args)

- `fn`: [``][function] asynchronous
- `args`: [``][array] its arguments

Wrap function adding async chain methods

### of(args)

- `args`: [``][array]

Applicative f => a -> f a

### concat(fn1, fn2)

- `fn1`: [``][function]
- `fn2`: [``][function]

Monoid m => a -> a -> a

### fmap(fn1, f)

- `fn1`: [``][function]
- `f`: [``][function]

Functor f => (a -> b) -> f a -> f b

### ap(fn, funcA)

- `fn`: [``][function]
- `funcA`: [``][function]

Applicative f => f (a -> b) -> f a -> f b

### memoize(fn)

- `fn`: [``][function] sync or async

_Returns:_ [``][function] memoized

Create memoized function

### class Memoized

#### Memoized.prototype.constructor()

#### Memoized.prototype.clear()

#### Memoized.prototype.add(key, err, data)

#### Memoized.prototype.del(key)

#### Memoized.prototype.get(key, callback)

#### Memoized.prototype.on(eventName, listener)

- `eventName`: [``][string]
- `listener`: [``][function] handler

Add event listener

_Example:_

```js
const memoized = new Memoized();
memoized.on('memoize', (err, data) => { ... });
memoized.on('add', (key, err, data) => { ... });
memoized.on('del', (key) => { ... })
memoized.on('clear', () => { ... });
```

#### Memoized.prototype.emit(eventName, args)

- `eventName`: [``][string]
- `args`: `` rest arguments

Emit Memoized events

### poolify(factory, min, norm, max)

### queue(concurrency)

- `concurrency`: [``][number] simultaneous and asynchronously executing
tasks

_Returns:_ [``][queue]

Create Queue instance

### class Queue

Queue constructor

#### Queue.prototype.constructor(concurrency)

- `concurrency`: [``][number] asynchronous concurrency

Queue constructor

#### Queue.prototype.wait(msec)

- `msec`: [``][number] wait timeout for single item

_Returns:_ [``][this]

Set wait before processing timeout

#### Queue.prototype.throttle(count\[, interval\])

- `count`: [``][number] item count
- `interval`: [``][number] per interval, optional default: 1000 msec

_Returns:_ [``][this]

Throttle to limit throughput

#### Queue.prototype.add(item\[, factor\[, priority\]\])

- `item`: [``][object] to be added
- `factor`: [``][number]|[``][string] type, source, destination
or path, optional
- `priority`: [``][number] optional

_Returns:_ [``][this]

Add item to queue

#### Queue.prototype.next(task)

- `task`: [``][array] next task [item, factor, priority]

_Returns:_ [``][this]

Process next item

#### Queue.prototype.takeNext()

_Returns:_ [``][this]

Prepare next item for processing

#### Queue.prototype.pause()

_Returns:_ [``][this]

Pause queue

This function is not completely implemented yet

#### Queue.prototype.resume()

_Returns:_ [``][this]

Resume queue

This function is not completely implemented yet

#### Queue.prototype.clear()

_Returns:_ [``][this]

Clear queue

#### Queue.prototype.timeout(msec, onTimeout)

- `msec`: [``][number] process timeout for single item
- `onTimeout`: [``][function]

_Returns:_ [``][this]

Set timeout interval and listener

#### Queue.prototype.process(fn)

- `fn`: [``][function]
- `item`: [``][object]
- `callback`: [``][function]
- `err`: [``][error]|[``][null]
- `result`: ``

_Returns:_ [``][this]

Set processing function

#### Queue.prototype.done(fn)

- `fn`: [``][function] done listener
- `err`: [``][error]|[``][null]
- `result`: ``

_Returns:_ [``][this]

Set listener on processing done

#### Queue.prototype.success(listener)

- `listener`: [``][function] on success
- `item`: ``

_Returns:_ [``][this]

Set listener on processing success

#### Queue.prototype.failure(listener)

- `listener`: [``][function] on failure
- `err`: [``][error]|[``][null]

_Returns:_ [``][this]

Set listener on processing error

#### Queue.prototype.drain(listener)

- `listener`: [``][function] on drain

_Returns:_ [``][this]

Set listener on drain Queue

#### Queue.prototype.fifo()

_Returns:_ [``][this]

Switch to FIFO mode (default for Queue)

#### Queue.prototype.lifo()

_Returns:_ [``][this]

Switch to LIFO mode

#### Queue.prototype.priority(flag)

- `flag`: [``][boolean] default: true, false will disable priority mode

_Returns:_ [``][this]

Activate or deactivate priority mode

#### Queue.prototype.roundRobin(flag)

- `flag`: [``][boolean] default: true, false will disable roundRobin
mode

_Returns:_ [``][this]

Activate or deactivate round robin mode

#### Queue.prototype.pipe(dest)

- `dest`: [``][queue] destination queue

_Returns:_ [``][this]

Pipe processed items to different queue

### throttle(timeout, fn, ...args)

- `timeout`: [``][number] msec interval
- `fn`: [``][function] to be throttled
- `args`: [``][array] arguments for fn, optional

_Returns:_ [``][function]

Get throttling function, executed once per interval

### debounce(timeout, fn, ...args)

- `timeout`: [``][number] msec
- `fn`: [``][function] to be debounced
- `args`: [``][array] arguments for fn, optional

Debounce function, delayed execution

### timeout(timeout, fn, callback)

- `timeout`: [``][number] time interval
- `fn`: [``][function] to be executed
- `callback`: [``][function] callback(...args), on done
- `args`: [``][array]

Set timeout for asynchronous function execution

## Contributors

- Timur Shemsedinov (marcusaurelius)
- See github for full [contributors list](https://github.com/metarhia/metasync/graphs/contributors)

[asynciterable]: https://tc39.github.io/ecma262/#sec-asynciterable-interface
[asynciterator]: #class-asynciterator
[collector]: #class-collector
[queue]: #class-queue
[object]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object
[function]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function
[promise]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
[array]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array
[error]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error
[boolean]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Boolean_type
[null]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Null_type
[number]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Number_type
[string]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#String_type
[iterable]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols
[this]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this