/async-magic

Promises FTW! A pure promised based, async toolbox for Node.js >=7.6

Primary LanguageJavaScriptMIT LicenseMIT

Build Status

async-magic

Promises FTW! A pure promised based, straight forward async library for Node.js >=7.6.

yarn add async-magic --save

Features

  • Convert callback based functions into promised based once (with named functions)
  • Advanced promised based control flows (parallel, series)
  • Run a set of promised functions in parallel with given number of maximum parallel tasks
  • Queue promised based function including arguments
  • Standalone, no external dependencies required
  • Designed to run with the pure power of native Promise, await and async function
  • No backward compatibility layer

API

  • promisify - Promisify a callback-based function
  • promisifyAll - Promisify a set of callback-based functions
  • parallel - Executes multiple PromiseResolver in parallel with given task limit
  • series - Executes multiple PromiseResolver in series
  • PromiseResolver - Utility function to cache a promised function including arguments for resolving. Required for advanced, promised based, control flows
  • wait - Promise.all alias
  • sleep - Intercept the current function execution
  • Mutex - asynchronous Mutex lock pattern

promisify

Description: Promisify a callback-based function

Requirements:

  • Last function argument has to be the callback (Nodejs Standard)
  • The first argument of the callback has to be a possible error (Nodejs Standard)

Syntax: fn:function = promisify(fn:function, [functionName:String])

Arguments:

  • fn:function - the callback based function which should be converted into a promise based
  • functionName:String(optinal) - an optional name which is used as native js function name

Example:

const _asyncMagic = require('async-magic');
const _fs = require('fs');

// create promisified fs-stat. set "stat" as native function name
const fsStat = _asyncMagic.promisify(_fs, 'stat');

// use promisified version
(async function(){
    const fstats = await _fsStat(__filename);
    console.log('Size:', fstats.size);
})();

promisifyAll

Description: Promisify a set of callback-based functions

Syntax: promisifiedFunctionSet:Object = promisifyAll(functionSet:Object, functionNames:StringArray)

Arguments:

  • functionSet:Object - a set of functions identified by the objects keys
  • functionNames:StringArray - a list of the object keys which should be promisified (names are also taken as native function names!)

Example:

Promisify some fs functions. Just as showcase, take a look at fs-magic - it is based on async-magic.

const _asyncMagic = require('async-magic');
const _fs = require('fs');

// list of fs methods to promisify
const fsApi = [
    'access',
    'appendFile',
    'chmod'
];

// create promisified fs version
const _fsPromised = _asyncMagic.promisifyAll(_fs, fsApi);

// use promisified version
(async function(){
    const fstats = await _fsPromised.stat(__filename);
    console.log('Size:', fstats.size);
})();

parallel

Description: Executes multiple PromiseResolver in parallel with given task limit

Syntax: results:array = parallel(resolvers:array, [limit:int=1000])

const _asyncMagic = require('async-magic');
const _fsMagic = require('fs-magic');
const PromiseResolver = _asyncMagic.PromiseResolver;

(async function(){
    // task list
    const tasks = [];
    
    // stat a large list of files 
    tasks.push(PromiseResolver(_fsMagic.stat, 'file1.txt'));
    tasks.push(PromiseResolver(_fsMagic.stat, 'file2.txt'));
    ...
    tasks.push(PromiseResolver(_fsMagic.stat, 'fileN.txt'));
    
    // resolves the promise with predefined arguments
    // limit the number of parallel executed promises to 100 (IO handle limitation)
    const stats = await _asyncMagic.parallel(tasks, 100);
})();

series

Description: Executes multiple PromiseResolver in series

Syntax: results:array = series(resolvers:array, [failOnError:boolean=true])

In case failOnError is not set, the resultset will contain the error object thrown during execution. Otherwise the executor will abort directly if an error has been thrown.

const _asyncMagic = require('async-magic');
const _fsMagic = require('fs-magic');
const PromiseResolver = _asyncMagic.PromiseResolver;

(async function(){
    // task list
    const tasks = [];
    
    // stat a large list of files 
    tasks.push(PromiseResolver(_fsMagic.stat, 'file1.txt'));
    tasks.push(PromiseResolver(_fsMagic.stat, 'file2.txt'));
    ...
    tasks.push(PromiseResolver(_fsMagic.stat, 'fileN.txt'));
    
    // resolves the promise with predefined arguments)
    const stats = await _asyncMagic.series(tasks);
})();

PromiseResolver

Description: Utility function to cache a promised function including arguments for resolving. Required for advanced, promised based, control flows

Syntax: p:PromiseResolver = PromiseResolver(fn:function, [...args:any])

const _asyncMagic = require('async-magic');
const _fsMagic = require('fs-magic');
const PromiseResolver = _asyncMagic.PromiseResolver;

(async function(){
    // caches the function with given arguments
    const task = PromiseResolver(_fsMagic.stat, 'file1.txt');
    
    // resolves the promise with predefined arguments
    const stat = await task.resolve();
})();

wait

Description: A Promise.all alias - waits until each promise has been completed or a single error occurs

Syntax: p:Promise = wait(promises:Array)

const _asyncMagic = require('async-magic');
const _fsMagic = require('fs-magic');

// stat multiple files at once
(async function(){
    const stats = await _asyncMagic.wait([
        _fsMagic.stat('file1.txt'),
        _fsMagic.stat('file2.txt'),
        _fsMagic.stat('file3.txt')
    ]);
})();

sleep

Description: Intercept the current function exection for a given time asynchronous (does not stop the global event loop!)

Syntax: p:Promise = sleep(time:int)

const _asyncMagic = require('async-magic');

(async function(){
    console('Hello..');

    // stop function execution for 1s (asynchronous!)
    await _asyncMagic.sleep(1000);

    console.log('World');
})();

Mutex

Description: Mutex lock pattern for asynchronous operations

Syntax: p:Mutex = new Mutex()

const _asyncMagic = require('async-magic');

(async function IOtask(){
   // create Mutex
    const mutex = new _asyncMagic.Mutex();

    // acquire lock
    await mutex.acquire();

    // do something exclusively
    await directIoOperation();

    // unlock
    mutex.release();
})();

FAQ

What is the difference between named and anonymous functions ? (promisify)

Named functions contains its function-name as immutable .name attribute. This is especially useful during debugging, because the stacktrace will display the plain-text function name instead of "anonymous"

const _asyncMagic = require('../async-magic');
const _fs = require('fs');

// create a unnamed (standard) version and a named one
const promisedStat = _asyncMagic.promisify(_fs.stat);
const namedPromisedStat = _asyncMagic.promisify(_fs.stat, 'stat');

// show function names (immutable .name attribute is set)
console.log(promisedStat.name); //=> anonymous
console.log(namedPromisedStat.name); //=> stat

Any Questions ? Report a Bug ? Enhancements ?

Please open a new issue on GitHub

License

async-magic is OpenSource and licensed under the Terms of The MIT License