hussain hussain - 4 months ago 17
Javascript Question

How to make sure call is asynchronous?

I have a program where user first create a file once file is created i am appending data to the file that is coming from client consistently.The below code is working as expected. I am new to nodejs so just want to get an expert opinion in case when multiple users creating and recording files on their machines at same time, will it work asynchronously or do i need to make some changes to the code ?

io.js

socket.on('createlogfile', function() {
logsRecording.userLogs(function(filename) {
socket.emit('filename', filename);
});

});
socket.on('startrecording', function(obj) {
logsRecording.recordLogs(obj);
});


server.js

userLogs: function (callback) {
var filename = uuid.v4() + '.log';
var file = filePath + '/' + filename;
fs.openSync(file, 'a',function () {
console.log('file created');
});
console.log('userLogs');
callback(filename);
},

recordLogs: function (obj) {
var dir = './app/records/templogs'
var fileAppend = dir + '/'+ obj.file;
console.log('data from recording', obj.data);
fs.readdir(dir, function(err, items) {
items.forEach(function(file){
if(obj.file === file){
fs.appendFile(fileAppend, obj.data+ "\r\n", null, 'utf8', function (err) {
if (err) throw err;
});
console.log('filename in records',obj.file);
}
});
});
}

Answer

You are using fs.openSync, which is synchronous and as such can hang the event loop.

You should be using fs.open and callback inside it:

userLogs: function (callback) {
    var filename = uuid.v4() + '.log';
    var file = filePath + '/' + filename;
    fs.open(file, 'a', function (err) {
        console.log('file created');
            console.log('userLogs');
            callback(err, filename);
    });
},

And you can flatten recordLogs using async.

Also, it is bad practice to throw error in synchronous function, you should be passing the error in the callback.

As a last tip, Array.forEach is synchronous, and can hang the process, you should be using async.each

recordLogs: function (obj, callback) {
    var dir = './app/records/templogs'
    var fileAppend = dir + '/'+ obj.file;
    console.log('data from recording', obj.data);
    async.waterfall([
        (callback) => {
            fs.readdir(dir, (err, items) => {
                callback(err, items);
            });
        },
        (items, callback) => {
            async.each(items, (file, callback) => {
                if(obj.file === file) {
                    fs.appendFile(fileAppend, obj.data+ "\r\n", null, 'utf8', function (err) {
                        callback(err);
                    });
                    console.log('filename in records',obj.file);
                } else {
                    callback();
                }
            }, (err) => {
                callback(err);
            });
        }
    ], (err, file) => {
        if(callback) {
            callback(err);
        }
    });
}