3

I am looking to bind a variable to my request object so when the callback is made I have access to this variable.

Here is the library: https://github.com/request/request

Here is my code.

var request = require('request');    
for (i = 0; i < cars.length; i++) { 


  request({
      headers: { 'Content-Type': 'application/json'},
      uri: 'https://example.com',
      method: 'POST',
      body: '{"clientId": "x", "clientSecret": "y"}'
    },
    function(err, res, body){
      // I want to put the correct i here.
      // This outputs cars.length almost everytime.
      console.log(i);
  });

}
Jimmy Scray
  • 144
  • 2
  • 14
  • the body is a string? Have you tried `JSON.stringify({"clientId": "x", "clientSecret": "y"})` – mugabits Apr 22 '16 at 20:08
  • You need to use [IIFE](https://en.wikipedia.org/wiki/Immediately-invoked_function_expression) to have a separate scope for every index. – Ioan Apr 22 '16 at 20:08
  • See http://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example. – Ioan Apr 22 '16 at 20:11
  • ^ I feel this is different since I am using a request object. – Jimmy Scray Apr 22 '16 at 20:21

1 Answers1

9

You already have access to the i, ripe for the taking, with a closure!

var request = require('request');    
for (i = 0; i < cars.length; i++) { 

  (function(i){
    request({
        headers: { 'Content-Type': 'application/json'},
        uri: 'https://example.com',
        method: 'POST',
        body: '{"clientId": "myea1r4f7xfcztkrb389za1w", "clientSecret": "f0aQSbi6lfyH7d6EIuePmQBg"}'
      },
      function(err, res, body){
        // I want to put the correct i here.
        // This outputs cars.length almost everytime.
        console.log(i);
    });
  })(i);
}

The problem with your original code was that the async function happens long after the i value has changed, in this case it will be equal cars.length for each call of the async function.

By using a self-calling function, we pass in only the value of i that should be used for everything within the function.

aaronofleonard
  • 2,546
  • 17
  • 23
  • It has nothing to do with the fact that the function is asynchronous. – Ioan Apr 22 '16 at 20:10
  • @loan if the anonymous function was being called synchronously in his code, it would be executed with the expected value of `i`, wouldn't it? (Yes) https://jsfiddle.net/fv9aosxe/1/. If it were not called asynchronously, it would be called in the middle of the `for` loop, with the expected `i` value. Since it asynchronous, it inherently can only happen on, at the soonest, the next iteration of the event loop. In that case, it can only happen after the `for` loop has finished running. (Granted asynchronicity isn't the ONLY affecting concept here, but it is a core part of the reason.) – aaronofleonard Apr 22 '16 at 21:00
  • If you make a timeout instead of asynchronous function, you would see that every console.log will have the same value, 5. – Ioan Apr 22 '16 at 21:13
  • 1
    @loan timeout is an asynchronous function...perhaps this is coming down to semantics. For the purposes of the discussion, I'm saying an asynchronous function is a function call which is not called within the synchronous flow of the application during one particular iteration of the event loop. setTimeout will inherently be called after the current iteration of the event loop, even if it's set with 0. It is a very broad, but accurate definition of asynchronous for the purposes of this discussion. The key is the event loop :) – aaronofleonard Apr 22 '16 at 21:23