Mahtab Alam
Mahtab Alam

Reputation: 1870

Async each function

I'm trying to understand async each(coll, iteratee, callback) function to execute a function in parallel for each item of an array. From the async docs I understand that callback will be executed only once (when iteratee function will be executed for each item of the array).

And in the case of an error in the iteratee function, calling callback('some error message') will immediately call the callback function with error message.

Below is an example from the async docs for each function

each(coll, iteratee, callback)

// assuming openFiles is an array of file names
async.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');
    }
});

What I'm not able to understand is, what does calling callback() without argument does, it looks very strange to me that we call callback() with no argument when there is no error in the iteratee function. What does calling callback() or callback(null) do in case of no errors.

Can't we just remove those callback() or callback(null), when we actually mean to call the callback only once (when iteratee function is executed for all the elements of the array) rather than for each item of the array.

Upvotes: 0

Views: 3055

Answers (2)

hargasinski
hargasinski

Reputation: 851

What does calling callback() or callback(null) do in case of no errors.

Calling callback with no arguments or with null signals to async.each that the iteratee function finished executing on that item (file in the case of the example). When all of the iteratee functions have called their respective callback, or one of them passes an error to it's callback, async.each will call the original callback function passed to it.

To elaborate on that a little, async.js is designed to handle asynchronous functions. The benefit (or issue, depending on how you look at it), of an asynchronous function is that there is no way to tell when it will finish executing. The way to deal with this is to pass the asynchronous function another function, a callback, to execute when it is finished. The asynchronous function could pass any errors it encounters, or any data it retrieves, to the original calling function through the callback function. For example, fs.readFile passes the read file data, and any errors, through the callback function is it passed.

Can't we just remove those callback() or callback(null), when we actually mean to call the callback only once (when iteratee function is executed for all the elements of the array) rather than for each item of the array.

No, because async.js has to assume the iteratee function is asynchorous, and therefore, it has to wait for it to its callback. The callback passed to async.each is only called once.

The confusion may be caused by the variable names. An individual callback function is only meant to be called once. The callback function passed to async.each is not the same callback passed to the iteratee. Each time iteratee is invoked with a value in coll, it is passed a new callback function. That call of iteratee is only supposed to call the passed callback once (async will throw an error otherwise). This allows async to track if a call to the iteratee function has called its callback, and wait for the rest to call their respective callback. Once all of the callback functions are called, async.each knows all of the asynchorous iteratee function calls have finished executing, and that it can call the original callback passed to it.

This is one of the difficult aspects of creating docs. They have to concise enough that a developer can get information from them quickly, and also include enough detail that they can explain the concept, or the function. It's a hard balance to achieve sometimes.

Upvotes: 3

pfg
pfg

Reputation: 3577

Calling callback with no arguments adds to a counter inside of the .each function. This counter, when full is the thing that actually calls your callback. Without that, it would never know when it completed.

Upvotes: 0

Related Questions