0

I'm making a function that searches through a JSON API using an axios get function and then assigns a string to global variable img.

var img; //declaring the global variable
    axios.get('https://i8xla88513.execute-api.us-east-1.amazonaws.com/latest/items')
    .then(function (res){
      for(i in res.data){ //This searches through the API
        if(res.data[i].name === imgSearch){ 
          img = res.data[i].image; //This assigns a value to the global function
          break;
        }  
      }
    })

I need to call the img variable later in the script; however, when I do console.log(img) inside the function it shows what I want it to show, but if I do console.log(img) or do anything to call the variable outside the function, it shows up as undefined. What am I doing wrong here, and how do I make this modify the global variable img instead of a local one?

  • Couldn't reproduce. The img variable **does** store the URL of some image. Is the variable itself inside some closure/scope? – shrihankp Feb 22 '21 at 03:49

1 Answers1

1

It's a matter of timing. When you look at the variable outside the .then() handler, you're looking at the value BEFORE the promise has resolved and before your value has been set. If you put several console.log() statements at the various points in your code, you will see that you are attempting to examine and use the img variable BEFORE the callback has run and set the value.

This uncertainty of timing (you never know precisely when a promise is going to be resolved) is why you almost never use the pattern you show where you assign a value to a higher scoped variable inside some asynchronous callback. Instead, you either use the value inside the callback or you call some function from within the callback and pass it the value as a function argument. Then, and only then, do you know the value is available and ready for use.

To illustrate the timing issue, try this code:

var img; //declaring the global variable
    axios.get('https://i8xla88513.execute-api.us-east-1.amazonaws.com/latest/items')
    .then(function (res){
      for(i in res.data){ //This searches through the API
        if(res.data[i].name === imgSearch){ 
          console.log("about to set img");
          img = res.data[i].image; //This assigns a value to the global function
          break;
        }  
      }
    });
    console.log("about to inspect img");
    console.log(img);

When you run this, you will see the this sequence in the console:

  about to inspect img
  undefined
  about to set img

This shows you how you were attempting to use the variable BEFORE the asynchronous callback had been called so the variable had not yet been set with its value. This is because axios.get() is asynchronous and non-blocking. Calling it just initiates the http request and then the Javascript interpreter immediately executes the next lines of code after it (not inside the .then(), but after that). Then, sometime later when the axios call finishes, the promise resolves and it calls the .then() handler.

So, instead, do something like this:

axios.get('https://i8xla88513.execute-api.us-east-1.amazonaws.com/latest/items').then(function (res) {
  for(let i in res.data){ //This searches through the API
    if(res.data[i].name === imgSearch){ 
      let img = res.data[i].image;

      // call some function and pass the variable to that function
      callMyFunction(img);

      break;
    }  
  }
});

Also, note that for(i in res.data) is attempting to use an undeclared variable i which makes it an implicit global which is a bad thing to do in for loop. ALWAYS declare all variables before using them. In this case, this can be:

for (let i in res.data)

Of, if res.data is an Array, then this really should be:

  for(let obj of res.data) {
    if (obj.name === imgSearch) { 
      let img = obj.image;

      // call some function and pass the variable to that function
      callMyFunction(img);

      break;
    }  
  }

As you shouldn't be using in to iterate the elements of an array. That iterates the properties of an object which can include more items than just array elements. Use of to iterate an array.

jfriend00
  • 683,504
  • 96
  • 985
  • 979