0

I'm building an application in which I need to make sequentially numbered requests starting with a specified number. This is my first node.js project so I'm learning as I go but I'm stuck on this particular issue.

I need to pass along the id so that I can reference it later. Essentially, I need to use the data from the first request to make a second request to a different api. Most of the data made to the second request will come from the response of the first request but the id does not so I need to pass it along somehow.

const rp = require('request-promise');

var id = process.argv[2];
var numIterations = process.argv[3] || 5;
var apiRequests = [];

for (var i = 0; i < numIterations; i++) {
    var requestDetails = {
        uri: 'https://www.example.com/id=' + id,
        json: false
    };

    apiRequests.push(
        rp(requestDetails).then(
            function (data) {
                return {
                    id: id,
                    html: data 
                };
            }
        )
    );

    id++;
}

Promise.all(apiRequests)
    .then((results) => {
        for (var i = 0; i < results.length; i++) {
            console.log(results[i].id); continue;
        }
    }).catch(err => console.log(err));

If id = 1 and numIterations = 5 for example, then I would expect to see: 1 2 3 4 5

But instead I see: 5 5 5 5 5

I get why this happens because of how request-promise works but I'm not sure how best to resolve it.

lokisapocalypse
  • 100
  • 2
  • 9

1 Answers1

1

The result object of your apiRequest ({ id: id, html: data };) will create asynchronously after the promise got resolved. at that moment id variable has the latest value assigned to it. so all the result objects that have been creating will have the same value.

To solve the problem you should keep a reference of your id in each for step. So define an array that it keeps the generated ids and push each id into it, and as it has the same order as the apiRequests, you can then access to them by the index of the results.

var apiRequests = [];
var ids = [];
// ...
apiRequests.push(/* ... */);
ids.push(id);
// ...
console.log(ids[i]);

The alternative solution will be using let instead of var if it's possible. As well described here:

var is scoped to the nearest function block and let is scoped to the nearest enclosing block.

If you define a let variable inside for, a unique instance will create in each step and as it's referenced in your object it will be kept until you exit the function scope. So the implementation would be something like this:

for (var i = 0; i < numIterations; i++) {
    let finalId = id; // add this line
    var requestDetails = {
        uri: 'https://www.example.com/id=' + id,
        json: false
    };

    apiRequests.push(
        rp(requestDetails).then(
            function (data) {
                return {
                    id: finalId, // update this line
                    html: data 
                };
            }
        )
    );

    id++;
}

As advice try to use let and const instead of var

Mosius
  • 1,602
  • 23
  • 32
  • Thank you very much for your reply. As stated previously, I just started with node.js so I'm still feeling my way through things but this solved my problem. – lokisapocalypse Feb 03 '19 at 15:40