0

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);
    }
}

4
  • This is EXACTLY why promises were invented. They create a much more sane mechanism for chaining, nesting or branching asynchronous operations. Even better when used with await. Commented May 17, 2018 at 23:48
  • Reading your code, you're missing multiple callbacks, or calling the same one multiple times... As @jfriend00 said, you should be using promises. Commented May 17, 2018 at 23:49
  • uhmm but the modules used work with callbacks functions and these stuff.. Commented May 17, 2018 at 23:55
  • Yes, of course they do, but since we got promises now, why don't use them. Have a look at my answer, I ported your code to promises. Let me know if you have any doubts. Commented May 18, 2018 at 0:11

2 Answers 2

3

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));
Sign up to request clarification or add additional context in comments.

2 Comments

Why do const { promisify } = require('util'); instead of const promisify = require('util').promisify;? I know destructuring is the latest gizmo to play with, but why use it with just one property?
To be honest, I coded it on a project I had open, where eslint nags about destructuring, so I just went with the flow. Is still shorter though.
2

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.