be-async

0.1.8 • Public • Published

be-async Build Status via Travis CI

testling badge

be-async is a lighter version of the massively used async.js module, if you don't know what async.js is, I recommend you to visit the project on Github

It's a lighter version as many methods have been removed, and the rest have been rewritten for sake of compactness and homogenity.

The goal of this module is to slowly grow from this de-facto standard which async.js is, implementing new methods and practical control flows.

Install

npm install be-async

Replacing async.js

This module can be a 'drop in replacement' of async.js, but there are a few considerations:

  • Not every method is available. Mostly from the control flow section, I felt that many of these were not strictly necessary so I removed them. Please check twice if your project requires one of these.

  • All callbacks are required now to receive an error as the first argument. async.js wasn't doing this on the pretext of old Node.js truth methods not doing it too. You can always correct asynchronous methods that don't return errors using the utility 'ccurry', which can prefill callbacks with arguments in any position.

  • Tests were ported from the original async.js, but obviously this module has not been used in the wild enough, so be careful, it may break (but it shouldn't).

This library now adds some functionality which is not present in async.js:

  • A basic event emitter and a channel abstraction built on top of it, golang style.
  • Currying and callback currying functions, capable of dropping arguments too.
  • Table flipping, also known as zip.
  • Multi-dimensional array merge.

Documentation

The following is the original documentation of async.js with some modifications.

Pull requests are very welcome!

Collections

Control Flow

Events

Utils

Collections

### be.each(arr, iterator, callback)

Applies the function iterator to each item in arr, in parallel. The iterator is called with an item from the list, and a callback for when it has finished. If the iterator passes an error to its callback, the main callback (for the each function) is immediately called with the error.

Note, that since this function applies iterator to each item in parallel, there is no guarantee that the iterator functions will complete in order.

Arguments

  • arr - An array to iterate over.
  • iterator(item, callback) - A function to apply to each item in arr. The iterator is passed a callback(err) which must be called once it has completed. If no error has occurred, the callback should be run without arguments or with an explicit null argument.
  • callback(err) - A callback which is called when all iterator functions have finished, or an error occurs.

Examples

// assuming openFiles is an array of file names and saveFile is a function
// to save the modified contents of that file:
 
be.each(openFiles, saveFile, function(err){
    // if any of the saves produced an error, err would equal that error
});
// assuming openFiles is an array of file names 
 
be.each(openFiles, function( file, callback) {
  
  // Perform operation on file here.
  console.log('Processing file ' + file);
  
  if( file.length > 32 ) {
    console.log('This file name is too long');
    callback('File name too long');
  } else {
    // Do work to process file here
    console.log('File processed');
    callback();
  }
}, function(err){
    // if any of the file processing produced an error, err would equal that error
    if( err ) {
      // One of the iterations produced an error.
      // All processing will now stop.
      console.log('A file failed to process');
    } else {
      console.log('All files have been processed successfully');
    }
});

### be.eachSeries(arr, iterator, callback)

The same as each, only iterator is applied to each item in arr in series. The next iterator is only called once the current one has completed. This means the iterator functions will complete in order.


### be.eachLimit(arr, limit, iterator, callback)

The same as each, only no more than limit iterators will be simultaneously running at any time.

Note that the items in arr are not processed in batches, so there is no guarantee that the first limit iterator functions will complete before any others are started.

Arguments

  • arr - An array to iterate over.
  • limit - The maximum number of iterators to run at any time.
  • iterator(item, callback) - A function to apply to each item in arr. The iterator is passed a callback(err) which must be called once it has completed. If no error has occurred, the callback should be run without arguments or with an explicit null argument.
  • callback(err) - A callback which is called when all iterator functions have finished, or an error occurs.

Example

// Assume documents is an array of JSON objects and requestApi is a
// function that interacts with a rate-limited REST api.
 
be.eachLimit(documents, 20, requestApi, function(err){
    // if any of the saves produced an error, err would equal that error
});

### be.map(arr, iterator, callback)

Produces a new array of values by mapping each value in arr through the iterator function. The iterator is called with an item from arr and a callback for when it has finished processing. Each of these callback takes 2 arguments: an error, and the transformed item from arr. If iterator passes an error to his callback, the main callback (for the map function) is immediately called with the error.

Note, that since this function applies the iterator to each item in parallel, there is no guarantee that the iterator functions will complete in order. However, the results array will be in the same order as the original arr.

Arguments

  • arr - An array to iterate over.
  • iterator(item, callback) - A function to apply to each item in arr. The iterator is passed a callback(err, transformed) which must be called once it has completed with an error (which can be null) and a transformed item.
  • callback(err, results) - A callback which is called when all iterator functions have finished, or an error occurs. Results is an array of the transformed items from the arr.

Example

be.map(['file1','file2','file3'], fs.stat, function(err, results){
    // results is now an array of stats for each file
});

### be.mapSeries(arr, iterator, callback)

The same as map, only the iterator is applied to each item in arr in series. The next iterator is only called once the current one has completed. The results array will be in the same order as the original.


### be.mapLimit(arr, limit, iterator, callback)

The same as map, only no more than limit iterators will be simultaneously running at any time.

Note that the items are not processed in batches, so there is no guarantee that the first limit iterator functions will complete before any others are started.

Arguments

  • arr - An array to iterate over.
  • limit - The maximum number of iterators to run at any time.
  • iterator(item, callback) - A function to apply to each item in arr. The iterator is passed a callback(err, transformed) which must be called once it has completed with an error (which can be null) and a transformed item.
  • callback(err, results) - A callback which is called when all iterator calls have finished, or an error occurs. The result is an array of the transformed items from the original arr.

Example

be.mapLimit(['file1','file2','file3'], 1, fs.stat, function(err, results){
    // results is now an array of stats for each file
});

### be.filter(arr, iterator, callback)

Alias: select

Returns a new array of all the values in arr which pass an be truth test. This operation is performed in parallel, but the results array will be in the same order as the original. This method has been 'corrected' from the original version, the callbacks now both accept an error object and a correction with ccurry should be done to functions that don't call back with initial error arguments.

Arguments

  • arr - An array to iterate over.
  • iterator(item, callback) - A truth test to apply to each item in arr. The iterator is passed a callback(err, truthValue), which must be called with a boolean argument once it has completed.
  • callback(err, results) - A callback which is called after all the iterator functions have finished.

Example

be.filter(['file1','file2','file3'], be.ccurry(fs.exists, 0, 0, null), function(err, results){
    // results now equals an array of the existing files
});

### be.filterSeries(arr, iterator, callback)

Alias: selectSeries

The same as filter only the iterator is applied to each item in arr in series. The next iterator is only called once the current one has completed. The results array will be in the same order as the original.


### be.reject(arr, iterator, callback)

The opposite of filter. Removes values that pass an async truth test.


### be.rejectSeries(arr, iterator, callback)

The same as reject, only the iterator is applied to each item in arr in series.


### be.reduce(arr, memo, iterator, callback)

Aliases: inject, foldl

Reduces arr into a single value using an async iterator to return each successive step. memo is the initial state of the reduction. This function only operates in series.

For performance reasons, it may make sense to split a call to this function into a parallel map, and then use the normal Array.prototype.reduce on the results. This function is for situations where each step in the reduction needs to be async; if you can get the data before reducing it, then it's probably a good idea to do so.

Arguments

  • arr - An array to iterate over.
  • memo - The initial state of the reduction.
  • iterator(memo, item, callback) - A function applied to each item in the array to produce the next step in the reduction. The iterator is passed a callback(err, reduction) which accepts an optional error as its first argument, and the state of the reduction as the second. If an error is passed to the callback, the reduction is stopped and the main callback is immediately called with the error.
  • callback(err, result) - A callback which is called after all the iterator functions have finished. Result is the reduced value.

Example

be.reduce([1,2,3], 0, function(memo, item, callback){
    // pointless async:
    process.nextTick(function(){
        callback(null, memo + item)
    });
}, function(err, result){
    // result is now equal to the last value of memo, which is 6
});

### be.reduceRight(arr, memo, iterator, callback)

Alias: foldr

Same as reduce, only operates on arr in reverse order.


### be.detect(arr, iterator, callback)

Returns the first value in arr that passes an be truth test. The iterator is applied in parallel, meaning the first iterator to return true will fire the detect callback with that result. That means the result might not be the first item in the original arr (in terms of order) that passes the test. This method has been 'corrected' from the original version, the callbacks now both accept an error object and a correction with ccurry should be done to functions that don't call back with initial error arguments.

If order within the original arr is important, then look at detectSeries.

Arguments

  • arr - An array to iterate over.
  • iterator(item, callback) - A truth test to apply to each item in arr. The iterator is passed a callback(truthValue) which must be called with a boolean argument once it has completed.
  • callback(err, result) - A callback which is called as soon as any iterator returns true, or after all the iterator functions have finished. Result will be the first item in the array that passes the truth test (iterator) or the value undefined if none passed.

Example

be.detect(['file1','file2','file3'], be.ccurry(fs.exists, 0, 0, null), function(err, result){
    // result now equals the first file in the list that exists
});

### be.detectSeries(arr, iterator, callback)

The same as detect, only the iterator is applied to each item in arr in series. This means the result is always the first in the original arr (in terms of array order) that passes the truth test.


### be.sortBy(arr, iterator, callback)

Sorts a list by the results of running each arr value through an be iterator.

Arguments

  • arr - An array to iterate over.
  • iterator(item, callback) - A function to apply to each item in arr. The iterator is passed a callback(err, sortValue) which must be called once it has completed with an error (which can be null) and a value to use as the sort criteria.
  • callback(err, results) - A callback which is called after all the iterator functions have finished, or an error occurs. Results is the items from the original arr sorted by the values returned by the iterator calls.

Example

be.sortBy(['file1','file2','file3'], function(file, callback){
    fs.stat(file, function(err, stats){
        callback(err, stats.mtime);
    });
}, function(err, results){
    // results is now the original array of files sorted by
    // modified date
});

Sort Order

By modifying the callback parameter the sorting order can be influenced:

//ascending order
be.sortBy([1,9,3,5], function(x, callback){
    callback(err, x);
}, function(err,result){
    //result callback
} );
 
//descending order
be.sortBy([1,9,3,5], function(x, callback){
    callback(err, x*-1);    //<- x*-1 instead of x, turns the order around
}, function(err,result){
    //result callback
} );

### be.some(arr, iterator, callback)

Alias: any

Returns true if at least one element in the arr satisfies an async test. Once any iterator call returns true, the main callback is immediately called. This method has been 'corrected' from the original version, the callbacks now both accept an error object and a correction with ccurry should be done to functions that don't call back with initial error arguments.

Arguments

  • arr - An array to iterate over.
  • iterator(item, callback) - A truth test to apply to each item in the array in parallel. The iterator is passed a callback(err, truthValue) which must be called with a boolean argument once it has completed.
  • callback(err, result) - A callback which is called as soon as any iterator returns true, or after all the iterator functions have finished. Result will be either true or false depending on the values of the async tests.

Example

be.some(['file1','file2','file3'], be.ccurry(fs.exists, 0, 0, null), function(err, result){
    // if result is true then at least one of the files exists
});

### be.every(arr, iterator, callback)

Alias: all

Returns true if every element in arr satisfies an async test. This method has been 'corrected' from the original version, the callbacks now both accept an error object and a correction with ccurry should be done to functions that don't call back with initial error arguments.

Arguments

  • arr - An array to iterate over.
  • iterator(item, callback) - A truth test to apply to each item in the array in parallel. The iterator is passed a callback(err, truthValue) which must be called with a boolean argument once it has completed.
  • callback(err, result) - A callback which is called after all the iterator functions have finished. Result will be either true or false depending on the values of the async tests.

Example

be.every(['file1','file2','file3'], be.ccurry(fs.exists, 0, 0, null), function(err, result){
    // if result is true then every file exists
});

### be.concat(arr, iterator, callback)

Applies iterator to each item in arr, concatenating the results. Returns the concatenated list. The iterators are called in parallel, and the results are concatenated as they return. This method now guarantees original array order in the concatenated results.

Arguments

  • arr - An array to iterate over.
  • iterator(item, callback) - A function to apply to each item in arr. The iterator is passed a callback(err, results) which must be called once it has completed with an error (which can be null) and an array of results.
  • callback(err, results) - A callback which is called after all the iterator functions have finished, or an error occurs. Results is an array containing the concatenated results of the iterator function.

Example

be.concat(['dir1','dir2','dir3'], fs.readdir, function(err, files){
    // files is now a list of filenames that exist in the 3 directories
});

### be.concatSeries(arr, iterator, callback)

Same as concat, but executes in series instead of parallel.

Control Flow

### be.series(tasks, [callback])

Run the functions in the tasks array in series, each one running once the previous function has completed. If any functions in the series pass an error to its callback, no more functions are run, and callback is immediately called with the value of the error. Otherwise, callback receives an array of results when tasks have completed.

It is also possible to use an object instead of an array. Each property will be run as a function, and the results will be passed to the final callback as an object instead of an array. This can be a more readable way of handling results from series.

Note that while many implementations preserve the order of object properties, the ECMAScript Language Specifcation explicitly states that

The mechanics and order of enumerating the properties is not specified.

So if you rely on the order in which your series of functions are executed, and want this to work on all platforms, consider using an array.

Arguments

  • tasks - An array or object containing functions to run, each function is passed a callback(err, result) it must call on completion with an error err (which can be null) and an optional result value.
  • callback(err, results) - An optional callback to run once all the functions have completed. This function gets a results array (or object) containing all the result arguments passed to the task callbacks.

Example

be.series([
    function(callback){
        // do some stuff ...
        callback(null, 'one');
    },
    function(callback){
        // do some more stuff ...
        callback(null, 'two');
    }
],
// optional callback
function(err, results){
    // results is now equal to ['one', 'two']
});
 
 
// an example using an object instead of an array
be.series({
    one: function(callback){
        setTimeout(function(){
            callback(null, 1);
        }, 200);
    },
    two: function(callback){
        setTimeout(function(){
            callback(null, 2);
        }, 100);
    }
},
function(err, results) {
    // results is now equal to: {one: 1, two: 2}
});

### be.parallel(tasks, [callback])

Run the tasks array of functions in parallel, without waiting until the previous function has completed. If any of the functions pass an error to its callback, the main callback is immediately called with the value of the error. Once the tasks have completed, the results are passed to the final callback as an array.

It is also possible to use an object instead of an array. Each property will be run as a function and the results will be passed to the final callback as an object instead of an array. This can be a more readable way of handling results from parallel.

Arguments

  • tasks - An array or object containing functions to run. Each function is passed a callback(err, result) which it must call on completion with an error err (which can be null) and an optional result value.
  • callback(err, results) - An optional callback to run once all the functions have completed. This function gets a results array (or object) containing all the result arguments passed to the task callbacks.

Example

be.parallel([
    function(callback){
        setTimeout(function(){
            callback(null, 'one');
        }, 200);
    },
    function(callback){
        setTimeout(function(){
            callback(null, 'two');
        }, 100);
    }
],
// optional callback
function(err, results){
    // the results array will equal ['one','two'] even though
    // the second function had a shorter timeout.
});
 
 
// an example using an object instead of an array
be.parallel({
    one: function(callback){
        setTimeout(function(){
            callback(null, 1);
        }, 200);
    },
    two: function(callback){
        setTimeout(function(){
            callback(null, 2);
        }, 100);
    }
},
function(err, results) {
    // results is now equals to: {one: 1, two: 2}
});

### be.parallelLimit(tasks, limit, [callback])

The same as parallel, only tasks are executed in parallel with a maximum of limit tasks executing at any time.

Note that the tasks are not executed in batches, so there is no guarantee that the first limit tasks will complete before any others are started.

Arguments

  • tasks - An array or object containing functions to run, each function is passed a callback(err, result) it must call on completion with an error err (which can be null) and an optional result value.
  • limit - The maximum number of tasks to run at any time.
  • callback(err, results) - An optional callback to run once all the functions have completed. This function gets a results array (or object) containing all the result arguments passed to the task callbacks.

### be.waterfall(tasks, [callback])

Runs the tasks array of functions in series, each passing their results to the next in the array. However, if any of the tasks pass an error to their own callback, the next function is not executed, and the main callback is immediately called with the error.

Arguments

  • tasks - An array of functions to run, each function is passed a callback(err, result1, result2, ...) it must call on completion. The first argument is an error (which can be null) and any further arguments will be passed as arguments in order to the next task.
  • callback(err, [results]) - An optional callback to run once all the functions have completed. This will be passed the results of the last task's callback.

Example

be.waterfall([
    function(callback){
        callback(null, 'one', 'two');
    },
    function(arg1, arg2, callback){
      // arg1 now equals 'one' and arg2 now equals 'two'
        callback(null, 'three');
    },
    function(arg1, callback){
        // arg1 now equals 'three'
        callback(null, 'done');
    }
], function (err, result) {
   // result now equals 'done'    
});

### be.nextTick(callback)

Calls callback on a later loop around the event loop. In Node.js this just calls process.nextTick; in the browser it falls back to setImmediate(callback) if available, otherwise setTimeout(callback, 0), which means other higher priority events may precede the execution of callback.

This is used internally for browser-compatibility purposes.

Arguments

  • callback - The function to call on a later loop around the event loop.

Example

var call_order = [];
be.nextTick(function(){
    call_order.push('two');
    // call_order now equals ['one','two']
});
call_order.push('one')

Events

### be.Emitter()

Basic event emitter.


be.Emitter.on(type, callback)

Calls callback when an event of the supplied type is emitter by Emitter.emit(). Bound events are stored in a queue where each will be called asynchronously in the same order they were added. User must take care of removing them using Emitter.off() when they are not used anymore.

Arguments

  • type - The type of the event as a string.
  • callback - The function that will be called when this event is triggered.

Example

var call_order = [];
var emitter = new be.Emitter;
emitter.on('event', function(n){
    call_order.push(n);
});
emitter.on('event', function(n){
    call_order.push(+ 1);
});
emitter.emit('event', 1); // call_order now equals [1, 2]

be.Emitter.once(type, callback)

Same as Emitter.on() but callback will be called just once and then automatically removed from the queue.


be.Emitter.off(type, callback)

Removes callback from the event type queue.

Arguments

  • type - The type of the event as a string.
  • callback - The function that will be removed from the queue (must be externally referenced).

Example

var call_order = [];
var emitter = new be.Emitter;
var add = function(n){
    call_order.push(n);
};
emitter.on('event', add);
emitter.off('event', add);
emitter.emit('event', 1); // call_order now equals []

be.Emitter.emit(type, ...args)

Emits an event of the supplied type with the given variadic args.

Arguments

  • type - The type of the event as a string.
  • args - Variadic arguments which will be passed to the callback registered in the event type queue.

Example

var call_order = [];
var emitter = new be.Emitter;
var add = function(n){
    call_order.push(n);
};
emitter.on('event', add);
emitter.emit('event', 1); // call_order now equals [1]

### be.Channel(slots)

Basic evented channel, analog to golang channels.

Arguments

  • slots - Number of lat data slots which will be kept in a buffer while they cannot be delivered (no shifters).

be.Channel.push(...args)

Pushes an arbitrary number of data args to the channel.

Arguments

  • args - Variadic arguments which will be writen at once in the channel queue.

Example

var chan = new be.Channel;
chan.push({ sample: "data" }, { some: "more" });
chan.shift(function(){
    console.log(arguments); // { '0': { sample: "data" }, '1': { some: "more" } }
});

be.Channel.shift(callback)

Reads data from the channel, passing it as variadic arguments to callback. Once the data is consumed once it is removed from the channel.

Arguments

  • callback - The function consuming the data shifted from the channel.

Example

var ball = { hits: 0 };
var table = new Channel(1);
 
table.push(Object.create(ball));
setTimeout(table.push.bind(table), 1000);
 
function player(name, table){
    table.shift(function(ball){
        ball.hits++;
        console.log(name, ball.hits);
        setTimeout(table.push.bind(table, ball), 100);
    });
}
 
// When using a buffered Channel, one can add listeners
// after pushing data
 
player('ping', table);
player('pong', table);

Utils

### be.curry(fn, pos, drop, args)

Positional curry function. Returns a function fn with prefilled argument(s) args overwriting a number of arguments drop in position pos.

Arguments

  • fn - Function to be prefilled with arguments.
  • pos - Postion where the arguments should be placed.
  • drop - Number of arguments that will be overwritten or dropped.
  • args - Single value or array of arguments which will be applied to the curried function.

Example

var divide = function(a, b){ 
    return a / b 
};
var half = be.curry(divide, 1, 0, 2);
half(6); // => 3
 
// dropping arguments
require('fs').readFile('./index.js', be.curry(function(){
    console.log(arguments); // { 0: <contents of index.js> }
}, 0, 1));
 

### be.ccurry(fn, pos, drop, args)

Continuation positional curry function. Returns a funcion fn with a prefilled callback which will overwrite a number drop of arguments with a new set args in position pos.

Arguments

  • fn - Function to be prefilled with a prefilled callback.
  • pos - Postion where the arguments should be placed in the callback.
  • drop - Number of arguments that will be overwritten or dropped.
  • args - Single value or array of arguments which will be applied to the curried function.

Example

var exists = be.ccurry(require('fs').exists, 0, 0, null);
exists('./index.js', function(){
    console.log(arguments); // { 0: null, 1: true }
});
 
// dropping arguments
var readFile = be.ccurry(require('fs').readFile, 0, 1);
readFile('./index.js', function(){
    console.log(arguments); // { 0: <contents of index.js> }
});

### be.flip(table)

Flips a table (changes columns to rows and viceversa), which is represented as an array containing a set of arrays.

Arguments

  • table - An array of arrays, representing rows and columns.

Example

var table = [
    [1,2,3],
    [4,5,6]
];
console.log(flip(table)); // [[1,4],[2,5],[3,6]]
assert.deepEqual(table, be.flip(be.flip(table))); // double flip returns it to original state

### be.unbind(fn, ...args)

Does the opposite of Function.prototype.bind. It removes the function it's default context, leaving it for the user to pass it as the first argument. Useful to reuse standard library prototypal functions like String.prototype.replace. Like Function.prototype.bind, it takes variadic args which will be curried over the function returned.

Arguments

  • fn - Function to be unbound.
  • args - Variadic arguments which will be passed to the resulting function.

Example

var readFile = be.ccurry(require('fs').readFile, 0, 1);
readfile('./index.js', 
    be.unbind(String.prototype.replace, 'function(', 'function ('));

### be.pipe(...fns)

Returns a function which will pass it's argument to a series of piped variadic functions fns. The resulting function call is the verse of function composing, so it's more natural to read.

c(b(a(val))) -> be.pipe(a, b, c)(val);

Arguments

  • fns - Variadic function to be piped.

Example

var stat = be.ccurry(require('fs').stat, 0, 1);
var beautify = be.curry(JSON.stringify, 1, 0, [null, 4]);
stat('./index.js', be.pipe(beautify, console.log));

### be.merge(array)

Merges subarrays into one big array. The equivalent of performing Array.concat on each subarray against the previous one.

Arguments

  • array - Array containing subarrays.

Example

var arr = [[1], [2, 3], [4, 5, 6]];
console.log(be.merge(arr)); // => [1, 2, 3, 4, 5, 6]

### be.once(fn)

Returns a function which calls the provided function fn just once. For the next calls, it will be performing no operation.

Arguments

  • fn - Function to prevent calling more than once.

Example

var doSomething = function(){
    console.log('beep');
}
var doSomethingOnce = be.once(doSomething);
doSomethingOnce(); // => beep
doSomethingOnce(); // => 

### be.noConflict()

Changes the value of be-async back to its original value, returning a reference to the be-async object.

Package Sidebar

Install

npm i be-async

Weekly Downloads

56

Version

0.1.8

License

none

Last publish

Collaborators

  • aynik