0

In my application, I am trying to read a file and then write the contents of the file to another file.

I have used bluebird promises to do this. I need help to confirm that my understanding on using promises is right in my implementation.

The questions that I have is,

  1. In my example, I am first reading the file, then once the file read the file, I am writing the contents into another file in my next '.then' block. Once the contents are written into a file I need log a message. I have included that in the second '.then' block. I need to know whether my understanding is correct on promises. will the second '.then' block works as the callback function for writefile statement?

  2. I need to write more meaningful log messages. Different error messages if an error occurs while reading the file and writing the file. How can I do this with catch blocks?

Thanks in advance!

The code example is below.

var Promise = require("bluebird");
var fs = Promise.promisifyAll(require("fs"));
var logger = require("./logger.js")
var projectJSON = require("../project.json");

var harPath = projectJSON.project.harfile.location;
var harFileNames = projectJSON.project.transactions.transactionsName;
var harFilePath;
var harFiles = {};
var writeFilePath = "../temp/"


harFileNames.forEach(function(harFileName){
    harFilePath = harPath + "/" + harFileName + ".har";

    fs.readFileAsync(harFilePath, "utf-8")
        .then(function(data){
            fs.writeFile(writeFilePath + harFileName + ".json", data);
            test = data;

        })
        .then(function(){
            console.log("data written successfully: ");

        })
        .catch(function(err){
            logger.error("error", "Error reading har files from location!");

        });

});

1 Answer 1

1

If you want to capture each error separately, then you can put an error handler immediately after each operation so you can directly capture that particular error.

Then, to propagate the error, you can rethrow the error value.

Then, you want to switch to fs.writeFileAsync() so everything is async and is using promises.

Then, you need to return the promise from fs.writeFileAsync().

var Promise = require("bluebird");
var fs = Promise.promisifyAll(require("fs"));
var logger = require("./logger.js")
var projectJSON = require("../project.json");

var harPath = projectJSON.project.harfile.location;
var harFileNames = projectJSON.project.transactions.transactionsName;
var harFilePath;
var harFiles = {};
var writeFilePath = "../temp/"


harFileNames.forEach(function(harFileName){
    harFilePath = harPath + "/" + harFileName + ".har";

    fs.readFileAsync(harFilePath, "utf-8")
        .then(function(data){
            harFiles[JSON.parse(data).log.pages[0].id] = JSON.parse(data);
            return data;
        }).catch(err) {
            logger.error("error", "Error reading har files from location!");
            throw err;      // propagate error
        }).then(function(data){
            return fs.writeFile(writeFilePath + harFileName + ".json", data).catch(function(err) {
                logger.error("error", "Error writing to harFile!");
                throw err;   // propagate error
            });
        }).then(function(){
            console.log("data written successfully: ");
        }).catch(function(err){
            // either one of the errors
        });

});

Keep in mind that when you have a .catch() handler, the error is considered "handled" and the resulting promise becomes fulfilled, not rejected. So, if you want to capture the error in a particular spot (so you know exactly where it came from), but you want the resulting promise to remain rejected, then you can either return a rejected promise or rethrow the same error.


Per your additional question about how to return harFiles, you will need a surrounding promise that gets resolved with harFiles when everything is done. Bluebird's Promise.map() is useful for that as it will both do the iteration for you and return a master promise. Here's how that part of the code could look:

function someFunc() {

    var harPath = projectJSON.project.harfile.location;
    var harFileNames = projectJSON.project.transactions.transactionsName;
    var harFilePath;
    var harFiles = {};
    var writeFilePath = "../temp/"

    return Promise.map(harFileNames, function(harFileName) {
        harFilePath = harPath + "/" + harFileName + ".har";

        return fs.readFileAsync(harFilePath, "utf-8")
            .then(function(data){
                harFiles[JSON.parse(data).log.pages[0].id] = JSON.parse(data);
                return data;
            }, function(err) {
                logger.error("error", "Error reading har files from location!");
                throw err;      // propagate error
            }).then(function(data){
                return fs.writeFile(writeFilePath + harFileName + ".json", data).catch(function(err) {
                    logger.error("error", "Error writing to harFile!");
                    throw err;   // propagate error
                });
            }).then(function(){
                console.log("data written successfully: ");
            }).catch(function(err){
                // either one of the errors
            });

    }).then(function() {
        // all results are in harFiles array here
        return harFiles;
    });
}

someFunc().then(function(hFiles) {
    // hFiles should be your files object
});
Sign up to request clarification or add additional context in comments.

8 Comments

Thank you for your answer. In your example, you have thrown errors in each catch block in order to make the resulting promises rejected, is it? One more question, This block of code is inside a function. Once it reads all the file and write them in a new location, as written in the example, I want to return the harFiles object array. when I include my return line after the for each loop it returns 'undefined' because of async behavior. How can nI do this?
@Hamza - Yes, the throw err lines are to make sure the resulting promise stays rejected so further operations in this chain are not attempted and so that the rejected reason gets all the way through to the end. I added another section to my answer about returning harFiles.
Thank you very much for the help.
I tried ur second solution, but it did not work for me. inorder to test values in my harFiles object, I added a loop to output the values in 'then' section, but didn't work.
@Hamza - Did you use a .then() when calling the containing function. See the extra explanation I added to the 2nd code example in my answer.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.