kramer65
kramer65

Reputation: 53873

How to handle javascript scope

I've got a simple javascript loop and a function with a callback in there and I'm struggeling with adding

console.log(accounts);  // logs this: ["123", "456"]
for (var i = 0; i < accounts.length; i++) {
  var currentAccount = accounts[i];
  console.log(currentAccount);  // first logs "123" and then "456" as expected

  meta.getBalance.call(account, {from: currentAccount}).then(function(value) {
    console.log(currentAccount);  // logs "456" twice
    console.log(value.value());  // logs the same value corresponding to "123" twice
  });
}

I presume that it logs "456" twice within the callback because it is an async call or something. But I'm unsure how I can solve this.

Any idea?

[EDIT]

I added one more console.log to it, which logs the value returned by the callback. To my surprise, that logs the same value twice, which corresponds to 123, instead of to 456. WHY OH WHY?! How in godsname can that be?!

Upvotes: 1

Views: 46

Answers (4)

CMR
CMR

Reputation: 933

You can pass your current value to a function, that return a function that gets called and has access to your value. Thats called Closures.

var accounts = ["123", "456"];
for (var i = 0; i < accounts.length; i++) {
  var currentAccount = accounts[i];
  console.log(currentAccount);  // first logs "123" and then "456" as expected

  promise('account', {from: currentAccount}).then(currentAccount => res => {
        console.log(currentAccount) // 123, then 456
  });
}

function promise() {
  return new Promise((res, rej) => res());
}

Upvotes: 0

M. F.
M. F.

Reputation: 1744

In the callback you log the currentAccount variable, which comes from the outer scope and is being assigned in the for loop.

Most likely, when your async call returns from its first call (made when currentAccount was "123"), currentAccount has already taken the value of the 2nd array element "456" inside the for loop.

Can you try to log the value argument passed to the callback instead? You should see 2 distinct values being returned, one for account "123" and another for account "456".

Upvotes: 0

Yaron Schwimmer
Yaron Schwimmer

Reputation: 5357

You can use a closure.

function cbGenerator(account) {
  return function(value) {
    console.log(account);
  }
}

Later...

for (var i = 0; i < accounts.length; i++) {
  var currentAccount = accounts[i];
  console.log(currentAccount);  
  var cb = cbGenerator(currentAccount);
  meta.getBalance.call(account, {from: currentAccount}).then(cb);
}

Upvotes: 3

ricky
ricky

Reputation: 1674

Call your function inside IIFE

console.log(accounts);  // logs this: ["123", "456"]
for (var i = 0; i < accounts.length; i++) {
  var currentAccount = accounts[i];
  console.log(currentAccount);  // first logs "123" and then "456" as expected

  (function(currentAccount){
         meta.getBalance.call(account, {from:currentAccount}).then(function(value) {
    console.log(currentAccount);  
          });    
  })(currentAccount);
  
}

Upvotes: 0

Related Questions