alinex-async

1.0.1 • Public • Published

Package: 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

NPM Downloads

The easiest way is to let npm add the module directly to your modules (from within you node modules directory):

npm install alinex-async --save

And update it to the latest version later:

npm update alinex-async --save

Always have a look at the latest changes.

Usage

Now it can be used like the normal async module:

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

each

Applies the function parallel to each element of array:

async.each [1..5](v, cb) ->
  # do something with element `v` 
  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.

eachLimit

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.

# set num to the number of parallel runs 
async.eachLimit [1..5]num(v, cb) ->
  # do something with element `v` 
  cb()
(err) ->
  # come here after all elements are processed or one element failed 
  # maybe check for errors 

eachSeries

The same as above but do each element one after the other.

# set num to the number of parallel runs 
async.eachSeries [1..5](v, cb) ->
  # do something with element `v` 
  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.

forEachOf

Like each, except that it iterates over objects, and passes the key as the second argument to the iterator.

async.forEachOf obj(v, k, cb) ->
  # do something with element `k: v` 
  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.

forEachOfLimit

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.

# set num to the number of parallel runs 
async.forEachOfLimit objnum(v, k, cb) ->
  # do something with element `k: v` 
  cb()
(err) ->
  # come here after all elements are processed or one element failed 
  # maybe check for errors 

forEachOfSeries

The same as above but do forEachOf element one after the other.

# set num to the number of parallel runs 
async.forEachOfSeries obj(v, k, cb) ->
  # do something with element `k: v` 
  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.

map

Applies the function parallel to each element of array like each but will return an array of the results:

async.map [1..5](v, cb) ->
  # do something with element `v` 
  cb null+ 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.

mapLimit

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.

# set num to the number of parallel runs 
async.mapLimit [1..5]num(v, cb) ->
  # do something with element `v` 
  cb null+ 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 

mapSeries

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.

async.mapSeries [1..5](v, cb) ->
  # do something with element `v` 
  cb null+ 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 

mapOf

Like map, except that it iterates over objects, and passes the key as the second argument to the iterator.

obj = {one:1two:2three:3}
async.mapOf obj(v, k, cb) ->
  # do something with element `k: v` 
  cb null+ 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.

mapOfLimit

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.

# set num to the number of parallel runs 
obj = {one:1two:2three:3}
async.mapOfLimit objnum(v, k, cb) ->
  # do something with element `k: v` 
  cb null+ 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 

mapOfSeries

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.

obj = {one:1two:2three:3}
async.mapOfSeries obj(v, k, cb) ->
  # do something with element `k: v` 
  cb null+ 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 

filter

reject

Control flow

series

parallel

parallelLimit

whilst

doWhilst

until

doUntil

forever

waterfall

applyEach

applyEachSeries

queue

priorityQueue

retry

times

timesSeries

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:

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:

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.

once

The second and later calls will return with the same result:

fn = async.once (cb) ->
  time = process.hrtime()
  setTimeout ->
    cb nulltime[1]
  1000

Use this to make some initializations which only have to run once but neither function may start because it is not done:

async.parallel [ fnfn ](err, results) ->
  # same as with `once.atime` 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 

onceSkip

A function may be wrapped with the once method:

fn = async.onceSkip (a, b, cb) -> cb null+ b

And now you can call the function as normal but on the second call it will return imediately without running the code:

fn 23(err, x) ->
  // x will now be 5
  fn 29(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.

onceThrow

Throw an error if it is called a second time:

fn = async.onceThrow (a, b, cb) -> cb null+ b

If you call this method multiple times it will throw an exception:

fn 23(err, x) ->
  # x will now be 5 
  fn 29(err, x) ->
    # will neither get there because an exception is thrown above 

onceTime

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.

fn = async.onceTime (cb) ->
  time = process.hrtime()
  setTimeout ->
    cb nulltime[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.

async.parallel [ fnfn ](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

http://www.apache.org/licenses/LICENSE-2.0

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.

Readme

Keywords

Package Sidebar

Install

npm i alinex-async

Weekly Downloads

13

Version

1.0.1

License

Apache-2.0

Last publish

Collaborators

  • alinex