L. Rebelo
L. Rebelo

Reputation: 97

Node.js write files in a for loop

I'm using a Google Trends API in node.js to get the popularity for several search terms.

I want to write a number of search words in an array and then access this array, calling the Google Trends API for each element and create a file for each element with the result of the API.

I tried this:

const googleTrendsApi = require("google-trends-api");
const fs = require('fs');

var cars = ["Saab", "Volvo", "BMW"]; 

for(var j = 0; j < 3; j++)
{
    googleTrendsApi.interestOverTime({keyword: cars[j]})
        .then(function(results){
            fs.writeFile(cars[j]+'.txt', results, function (err) {
                if (err) return console.log(err);
            })
        })
        .catch(function(err){
            console.error(err);
        });
    console.log(cars[j]);
};

The problem is that this method does not work (it creates no files) and I don't know why. How can I create multiple files in a for loop and write separate data in each of them?

Upvotes: 1

Views: 6447

Answers (1)

areller
areller

Reputation: 5238

When you run an async method inside a for loop, you have to take into account that the index might (and probably will) change to the last index (j = 3) once the async method returns. This is because the async method will probably take much longer to execute than the for loop to loop through all indices.

You can verify it by yourself by running:

for (var i = 0; i < 3; i++) {
    setTimeout(function () {
        console.log(i);
    }, 1000);
}

The output will be: 3 3 3

To overcome it, you put the body of the for loop inside a method

function execute(j) {
        googleTrendsApi.interestOverTime({keyword: cars[j]})
        .then(function(results){
            fs.writeFile(cars[j]+'.txt', results, function (err) {
                if (err) return console.log(err);
            })
        })
        .catch(function(err){
            console.error(err);
        });
}

And then your for loop will call execute(j):

for(var j = 0; j < 3; j++)
{
    execute(j);
    console.log(cars[j]);
}

execute(j) will make sure to capture the context of j even until after the async method executes.

Upvotes: 1

Related Questions