An extended version of the async library.
npm install alinex-asyncPackage: alinex-async
=================================================
> This package is deprecated and will not be developed further.
> You will find the once... method under util
> and for the rest use the real async package
> now in version 2.0.
This package will extend the async module with more useful functions. The package
will help in structuring in asynchronous programming.
- easy functions
- makes code more readable
- helps against the callback hell
This is not a complete new module but more an extension to the
async library by caolan. I decided to
wrap it instead of fork it to let the development of both parts be more independent.
So I don't need to update this library to get bugfixes of the core.
The changes to the core async are:
- added once... methods
- added mapOf... methods
> It is one of the modules of the Alinex Universe
> following the code standards defined in the General Docs.
Install
-------------------------------------------------

The easiest way is to let npm add the module directly to your modules
(from within you node modules directory):
`` sh`
npm install alinex-async --save
And update it to the latest version later:
` sh`
npm update alinex-async --save
Always have a look at the latest changes.
Usage
-------------------------------------------------
Now it can be used like the normal async
module:
` coffee`
async = require 'alinex-async'
Now you may use one of the following methods. All relevant functions are
documented whether they belong to this module directly or to the wrapped
async class.
Collections
-------------------------------------------------
Applies the function parallel to each element of array:
` coffeev
async.each [1..5], (v, cb) ->
# do something with element `
cb()
, (err) ->
# come here after all elements are processed or one element failed
# maybe check for errors
It will immediately skip all runs if any one sends an error back and calls the
resulting function with the error first occurred.
Also run processing of each element in parallel but limit the maximum parallel
runs to prevent overload. If the maximum number of parallel runs is reached the
rest will wait till any run finishes.
` coffeevset num to the number of parallel runs
async.eachLimit [1..5], num, (v, cb) ->
# do something with element `
cb()
, (err) ->
# come here after all elements are processed or one element failed
# maybe check for errors
The same as above but do each element one after the other.
` coffeevset num to the number of parallel runs
async.eachSeries [1..5], (v, cb) ->
# do something with element `
cb()
, (err) ->
# come here after all elements are processed or one element failed
# maybe check for errors
If one run will return an error all further elements won'T be processed.
Like each, except that it iterates over objects, and passes the key as
the second argument to the iterator.
` coffeek: v
async.forEachOf obj, (v, k, cb) ->
# do something with element `
cb()
, (err) ->
# come here after all elements are processed or one element failed
# maybe check for errors
It will immediately skip all runs if any one sends an error back and calls the
resulting function with the error first occurred.
Also run processing of forEachOf element in parallel but limit the maximum parallel
runs to prevent overload. If the maximum number of parallel runs is reached the
rest will wait till any run finishes.
` coffeek: vset num to the number of parallel runs
async.forEachOfLimit obj, num, (v, k, cb) ->
# do something with element `
cb()
, (err) ->
# come here after all elements are processed or one element failed
# maybe check for errors
The same as above but do forEachOf element one after the other.
` coffeek: vset num to the number of parallel runs
async.forEachOfSeries obj, (v, k, cb) ->
# do something with element `
cb()
, (err) ->
# come here after all elements are processed or one element failed
# maybe check for errors
If one run will return an error all further elements won'T be processed.
Applies the function parallel to each element of array like each but will return
an array of the results:
` coffeev
async.map [1..5], (v, cb) ->
# do something with element `
cb null, v + 1
, (err, results) ->
# come here after all elements are processed or one element failed
# if no failure occurred the results array will have:
# [2..6] in this example
It will immediately skip all runs if any one sends an error back and calls the
resulting function with the error first occurred.
Like with map this will give the same results but only run a maximum of limited
parallel calls. If the maximum number of parallel runs is reached the
rest will wait till any run finishes.
` coffeevset num to the number of parallel runs
async.mapLimit [1..5], num, (v, cb) ->
# do something with element `
cb null, v + 1
, (err) ->
# come here after all elements are processed or one element failed
# if no failure occurred the results array will have:
# [2..6] in this example
And this method will run all calls each after the other one in series. But also
the results array will be the same in the end.
` coffeev
async.mapSeries [1..5], (v, cb) ->
# do something with element `
cb null, v + 1
, (err) ->
# come here after all elements are processed or one element failed
# if no failure occurred the results array will have:
# [2..6] in this example
Like map, except that it iterates over objects, and passes the key as
the second argument to the iterator.
` coffeek: v
obj = {one:1, two:2, three:3}
async.mapOf obj, (v, k, cb) ->
# do something with element `
cb null, v + 1
, (err, result) ->
# come here after all elements are processed or one element failed
# if no failure occurred the result object will have:
# {one:2, two:3, three:4} in this example
It will immediately skip all runs if any one sends an error back and calls the
resulting function with the error first occurred.
Like with map this will give the same results but only run a maximum of limited
parallel calls. If the maximum number of parallel runs is reached the
rest will wait till any run finishes.
` coffeek: vset num to the number of parallel runs
obj = {one:1, two:2, three:3}
async.mapOfLimit obj, num, (v, k, cb) ->
# do something with element `
cb null, v + 1
, (err, result) ->
# come here after all elements are processed or one element failed
# if no failure occurred the result object will have:
# {one:2, two:3, three:4} in this example
And this method will run all calls each after the other one in series. But also
the results array will be the same in the end.
` coffeek: v
obj = {one:1, two:2, three:3}
async.mapOfSeries obj, (v, k, cb) ->
# do something with element `
cb null, v + 1
, (err, result) ->
# come here after all elements are processed or one element failed
# if no failure occurred the result object will have:
# {one:2, two:3, three:4} in this example
Control flow
-------------------------------------------------
Function wrapper
-------------------------------------------------
The following functions are used to wrap functions to give them more functionality.
You will get a resulting function which can be called any time.
In all of the following methods you may give an optional context to use as first
parameter. So to call it from class do so like:
` coffee`
class = Test
init: async.once this, (cb) ->
# method...
cb null, @status
That allows your function to access class members and methods. Keep in mind to use
=> if you use sub functions.
If you use it in module.exports then do it as follows:
` coffee
module.exports =
anyMethod: (cb) ->
# and so on
module.exports.init = async.once module.exports, (cb) ->
# method...
@anyMethod cb
`
Like you see above you have to declare this method separately so that the async.once
method can access the now already defined module.exports object.
The second and later calls will return with the same result:
` coffee`
fn = async.once (cb) ->
time = process.hrtime()
setTimeout ->
cb null, time[1]
, 1000
Use this to make some initializations which only have to run once but neither
function may start because it is not done:
` coffeeonce.atime
async.parallel [ fn, fn ], (err, results) ->
# same as with it will come here exactly after the`
# first call finished because the second one will get the
# result the same time
# results here will be the same integer, twice
fn (err, result) ->
# and this call will return imediately with the previous result
A function may be wrapped with the once method:
` coffee`
fn = async.onceSkip (a, b, cb) -> cb null, a + b
And now you can call the function as normal but on the second call it will
return imediately without running the code:
` coffee`
fn 2, 3, (err, x) ->
// x will now be 5
fn 2, 9, (err, x) ->
// err will now be set on the second call
You may use this helper in case of initialization (wait) there a specific
method have to run once before any other call can succeed. Or then events
are involved and an error event will trigger the callback and the end event will
do the same.
Throw an error if it is called a second time:
` coffee`
fn = async.onceThrow (a, b, cb) -> cb null, a + b
If you call this method multiple times it will throw an exception:
` coffee`
fn 2, 3, (err, x) ->
# x will now be 5
fn 2, 9, (err, x) ->
# will neither get there because an exception is thrown above
Only run it once at a time, queue following requests and send them the result
of the next run. All calls get the same result, but then the process is already
started it will list the following calls for the next round. This assures that
their result is from the newest data set because you may changed something
while the first run was already working.
` coffee`
fn = async.onceTime (cb) ->
time = process.hrtime()
setTimeout ->
cb null, time[1]
, 1000
And now you may call it multiple times but it will not run more than once
simultaneously. But all simultaneous calls will get the same result.
` coffee``
async.parallel [ fn, fn ], (err, results) ->
# will come here exactly after the first call finished (because the
# second will do so the same time)
# results here will be the same integer, twice
License
-------------------------------------------------
Copyright 2015-2016 Alexander Schilling
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
>
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.