Question

Here is a working test program without async:

var fs = require('fs');
function test() {
    var finalResponse = '', response = '';
    function showFinalResponse() {
        console.log(finalResponse);
    }
    function processTheFile(err, data) {
        if (err) {
            finalResponse = 'Could not read the file';
        } else {
            response += data;
            response += '</body></html>';
            finalResponse = response;
        }
        showFinalResponse();
    }
    function readTheFile(exists) {
        if (!exists) {
            finalResponse = 'File does not exist.';
            showFinalResponse();
        } else {
            response += '<!DOCTYPE html><html lang="en-US"><head></head><body>';
            fs.readFile('file.txt', 'utf8', processTheFile);
        }
    }
    fs.exists('file.txt', readTheFile);
};
test();

Here is my attempt at getting the same program to work with async waterfall. I'm having trouble with how to pass the callbacks around in the async and the fs calls.

var fs = require('fs');
var async = require('async');
function testAsync() {var finalResponse, response = '';
    async.waterfall( [
        function checkIfTheFileExists(done) {
            fs.exists('file.txt', done);
        },
        function readTheFile(err, exists, done) {
            response += '<!DOCTYPE html><html lang="en-US"><head></head><body>';
            fs.readFile('file.txt', 'utf8', done);
        },
        function processTheFile(err, data, done) {
            response += data;
            response += '</body></html>';
            finalResponse = response;
            done(null);
        } ],
        function showFinalResponse(err) {
            if (err) {
                if (err.code === 'ENOENT') {  // intended to test for file is missing.
                    finalResponse = 'File does not exist.';
                } else { // any other errors.
                    finalResponse = 'Could not read the file';
                }
                console.log(err);
            }
            console.log(finalResponse);
        }
    );
}
testAsync()

I can't get the async version to work. I'm getting confused with where the callbacks go.

Was it helpful?

Solution

fs.exists is an oddball in that it doesn't provide an error parameter to its callback function. Instead it only provides a single exists parameter that indicates whether the file was found or not. Presumably, if there was an error, exists would be false. As such you need to wrap its callback in your own function so that you can provide a separate error parameter to the waterfall callback:

async.waterfall( [
    function checkIfFileExists(done) {
        fs.exists('file.txt', function(exists) { done(null, exists); });
    },
    function makeSureFileExists(exists, done) {
    ...

Note the warning in the docs, however, that fs.exists shouldn't be used, typically.

OTHER TIPS

fs.exists('file.txt', done(null));

This calls done immediately. You need to pass the actual done function to fs.exists:

fs.exists('file.txt', done);

Same for the others.

Here is my final working version (in case it helps anyone else). Thanks again for your help!

var fs         = require('fs');
var async      = require('async');
var addErrParm = function (err, done) {return function(exists) {
    done(err, exists);
}}
function testAsync() {var finalResponse, response = '';
    function checkIfTheFileExists(done) {
        fs.exists('file.txt', addErrParm(null, done));
    }
    function readTheFile(exists, done) {
        if (!exists) {
            done('notFound');
        } else {
            response += '<!DOCTYPE html><html lang="en-US"><head></head><body>';
            fs.readFile('file.txt', 'utf8', done);
        }
    }
    function processTheFile(data, done) {
        response += (data || 'The file is empty') + '</body></html>';
        finalResponse = response;
        done(null);
    }
    function showFinalResponse(err) {
        if (err) {
            finalResponse = (err === 'notFound' ? 'File does not exist.' : 'Could not read the file');
        }
        console.log(finalResponse);
    }
    async.waterfall([ checkIfTheFileExists,
                      readTheFile,
                      processTheFile
    ], showFinalResponse);
}
testAsync()

So basically, async requires removing the err parameter (first argument) from all functions except the final callback, and it requires adding a callback ('done') as an extra parameter on all functions except the final callback.

Also, if there is no err parameter like with fs.exists, you have to create a function to simulate an err parameter so async can remove it.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top