Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using async module to fire a callback once all files are read

I'm using caolan's 'async' module to open an array of filenames (in this case, template file names).

Per the documentation, I'm using async.forEach(),so I can fire a callback once all operations have completed.

A simple test case is:

var async = require('async')
var fs = require('fs')

file_names = ['one','two','three'] // all these files actually exist

async.forEach(file_names, 
    function(file_name) {
        console.log(file_name)
        fs.readFile(file_name, function(error, data) {
            if ( error) {   
                console.log('oh no file missing')   
                return error
            } else {
                console.log('woo '+file_name+' found')
            }       
        })
    }, function(error) {
        if ( error) {   
            console.log('oh no errors!')
        } else {
            console.log('YAAAAAAY')
        }
    }
)

The output is as follows:

one
two
three
woo one found
woo two found
woo three found

I.e, it seems the final callback isn't firing. What do I need to do to make the final callback fire?

like image 693
mikemaccana Avatar asked Dec 21 '22 01:12

mikemaccana


2 Answers

The function that is being run across all items must take a callback, and pass its results to the callback. See below (I've also separated fileName to improve readability):

var async = require('async')
var fs = require('fs')

var fileNames= ['one','two','three']


// This callback was missing in the question.
var readAFile = function(fileName, callback) {
    console.log(fileName)
    fs.readFile(fileName, function(error, data) {
        if ( error) {   
            console.log('oh no file missing')   
            return callback(error)
        } else {
            console.log('woo '+fileName+' found')
            return callback()
        }       
    })
}

async.forEach(fileNames, readAFile, function(error) {
    if ( error) {   
        console.log('oh no errors!')
    } else {
        console.log('YAAAAAAY')
    }
})

Returns:

one
two
three
woo one found
woo two found
woo three found
YAAAAAAY
like image 81
mikemaccana Avatar answered Dec 24 '22 02:12

mikemaccana


This is the best way to do it in my opinion. The results param will have an array of strings containing the file data and all of the files will be read in parallel.

var async = require('async')
    fs    = require('fs');

async.map(['one','two','three'], function(fname,cb) {
  fs.readFile(fname, {encoding:'utf8'}, cb);
}, function(err,results) {
  console.log(err ? err : results);
});
like image 40
Michael Connor Avatar answered Dec 24 '22 02:12

Michael Connor