whathetech Javascript,node.js Promises in Javascript and Node.JS – Using Promise.all

Promises in Javascript and Node.JS – Using Promise.all

In this blog, we will try and understand how to use Promise.all and JS map functions to process all the items in an array asynchronously. If you are new to Promise, I suggest you take a look at http://whatthetech.co/promises-in-javascriptnode-js/
We will extend our previous example (link above) and extend it to add new functionality.
In promiseFun1, let us now make it to accept a parameter fileName and pass the same to fs.readFile. It will look something like this:

function promiseFun1(fileName) {
    return new Promise(function(resolve, reject) {
        fs.readFile(fileName,'utf8', (err, data) => {
            if (err) {
                return reject(err);
            } else {
                return resolve(data);
            }
        });
    });
}

Let us now create a new function which will take an array of filenames and pass it on to promiseFun1

function promiseMap() {
    //Create an array of 3 file names which needs to be read and processed
    var fileNames = ['test.txt', 'test1.txt', 'test2.txt'];
    //Instead of reading them synchronously, we will use promises to read them asynchronously
    var filePromise = fileNames.map(function(fileName) {
        return promiseFun1(fileName).then(sentences=>{
        console.log('Processing file = ', fileName);
            return wordCount(sentences);
        });
    });
    Promise.all(filePromise).then(numWords=>{
        console.log('Count of all files = ', numWords);
    })
    .catch(err=> {
        console.log(err);
    })
}

I have already created 3 files test.txt, text1.txt, test2.txt with different lengths in increasing order.
What fileNames.map does is to take one item from array at a time and pass it on forward. In this case we will be sending the fileName to promiseFun1.
When you call promiseFun1, do not forget to add return, if you do, then the Promise is not resolved properly and you will not get the result that you are expecting.

Note that this will not be executed until we call Promise.map
Once Promise.all is executed, all promises will be called and once all of them are resolved, it will come to the then part of the Promise.all

Response:

home@home-home-1:~/projects/whatthetech/promises$ node promises.js 
Processing file =  test.txt
Processing file =  test1.txt
Processing file =  test2.txt
Count of all files =  [ 83, 165, 247 ]

If you notice, the response that you get will be in the same order you have created your list.
Let us test this theory. In test1.txt, make sure you add lot of content. Now let us again execute this
Response:

home@home-home-1:~/projects/whatthetech/promises$ node promises.js 
Processing file =  test.txt
Processing file =  test2.txt
Processing file =  test1.txt
Count of all files =  [ 83, 17713, 247 ]

As you can see, test2.txt is printed before test1.txt but in the then of Promise.all, the order is maintained.

Another way to use Promise.all is to explicitly call functions in the all. Copy the following code and the execute.

function promiseFun2(fileName) {
    return new Promise(function(resolve, reject) {
        fs.readFile(fileName,'utf8', (err, data) => {
            if (err) {
                return reject(err);
            } else {
                wordCount(data).then(response=>{
                    return resolve(response);
                });
            }
        });
    });
}
function promiseMap_1() {
    Promise.all([promiseFun2('test.txt'), promiseFun2('test1.txt'), promiseFun2('test2.txt')]).then(numWords=>{
        console.log('index = ', numWords);
    })
    .catch(err=> {
        console.log(err);
    })
}
promiseMap_1();

Response:

vinod@vinod-home-1:~/projects/whatthetech/promises$ node promises.js 
index =  [ 83, 17713, 247 ]

This brings to an end of this post. In subsequent posts I will talk about bluebird Promises and how you could use them in some scenarios.

Tags: , ,