AndresSp
AndresSp

Reputation: 364

Problems with nested async functions (async waterfall in async series)

Please some help with this, im new with nodejs and this is a common issue and and im tried the examples in anothers posts here. I have problem when in the last function.

Im trying:

  1. Check if a data.json exists and create it with a some data with async.waterfall

function IfDataDontExistsCreate(callback)
{
    async.waterfall([ //If data dont exists
        function IfExistDataFile(callback) {
            fs.exists(path, function(exists){
                if(!exists)
                {
                    try {
                        const firstDataFile = {"readedPosts":{"id": []}};
                        const json = JSON.stringify(firstDataFile, null, 2);
                        callback(null, json);
                    } catch (error) {
                        callback(error);
                    }
                    
                }
            }
        )},
        function CreateDataFile(json ,callback) {
            fs.writeFile(path, json, function (err) {
                if(err) callback(err);
            })
        }
    ], function (err, callback) {
        if(err) throw err;
    });

    callback(null, callback);
}

  1. Read data.json, get data, add some info and save data.json with async.waterfall

function AppendtoDataFile(info, callback)
{
    async.waterfall([
        function ReadGetData(callback) {
            fs.readFile(path, (err, data) => {
                if(err) throw err;
                let datajson = JSON.parse(data.toString());
                datajson.readedPosts.id.push(info.toString()); //Add info
                callback(err, datajson)
            })
        },
        function WriteDataFile(data, callback) {
            const writeData = fs.writeFile(path, JSON.stringify(data, null, 2), function (err) {
                if(err) throw err;
                callback(err);
            })
        }
    ], function(err, callback)
    {
        if(err) throw err;
    });

    callback(null, callback);
}

  1. Join the functions with async.series

function AddPostID(postID, callback)
{
    async.series({
        one: function (callback) {
            IfDataDontExistsCreate(function () {
                callback(null, "DataFile Created");
            });
        },
        two: function (callback) {
            AppendtoDataFile(postID, function () {
                callback(null, "PostID added to Datafile");
            });
        }
    }),
    function (err, results) {
        if(error) throw err;
        console.log(results);
    }
}

Upvotes: 0

Views: 1189

Answers (2)

Marcos Casagrande
Marcos Casagrande

Reputation: 40404

Since your specific problems has been answered by @Raeesaa, I'm providing an alternative using promises and async/await, making the code more readable & clean

First of all, you can avoid fs.exists using fs.writeFile with wx flag:

'wx' - Like 'w' but fails if the path exists.


'use strict';

const fs = require('fs');
const { promisify } = require('util');

const writeFile = promisify(fs.writeFile);
const readFile = promisify(fs.readFile);

const path = '/tmp/foo.json';

async function IfDataDontExistsCreate() {
    const firstDataFile = {
        readedPosts: {
            id: []
        }
    };

    const json = JSON.stringify(firstDataFile, null, 2);

    try {

        await writeFile(path, json, { flag: 'wx' });
    } catch(e) {
        // If EEXIST means the file is already created, do nothing
        if(e.code !== 'EEXIST')
            throw e;
    }
}

async function AppendtoDataFile(info) {

    const data = await readFile(path, 'utf8');

    let datajson = JSON.parse(data);
    datajson.readedPosts.id.push(info.toString()); // Add info

    return writeFile(path, JSON.stringify(datajson, null, 2));
}

async function AddPostID(postID) {

    // Wait until the file is created
    await IfDataDontExistsCreate();
    console.log('DataFile Created');

    // We append after the file has been created
    await AppendtoDataFile(postID);
    console.log('PostID added to Datafile');

    return true;
}

AddPostID(5)
  .then(res => console.log('Done!'))
  .catch(err => console.error(err));

Upvotes: 3

Raeesaa
Raeesaa

Reputation: 3316

I am not sure about the exact problem you are facing but I do see an issue in your code. The callback in both functions IfDataDontExistsCreate and AppendtoDataFile is being called before async waterfall completes execution.

Calling callback(err, null) from final callback of async.waterfall and removing last line i.e. callback(null, callback) from both the functions should fix issue for you.

Upvotes: 2

Related Questions