2

everyone.

I have a problem about the 'callback function - scope of variable',

I wanna use the 'i in for loop' to 'the callback function User_UidSearch',

but I cannot use it.

(I hope the solution don't use the global variable.)


Task_TidSearchExecution = function(tid, callback) {
    var sql = "SELECT * FROM execution WHERE task = '" + tid + "'";
    dbclient.query(sql, function (err, results) {
        if (err || results.length <= 0)
            callback(false);
        else {
            console.log(results.length);
            for (var i = 0 ; i < results.length ; i++) {
                User_UidSearch(results[i].employee, function (user) {
                    console.log(i);
                    // results[i]['email'] = user.email;
                });
            }

            callback(results);
        }
    });
}

the "console.log(i);"

Recheck, this is wrong. -> Outputs are "undefined" of all.

undefined is "console.log(result[i]);"

But the "i" is keep '2' console twice, if results.length is 2.

I know becuz the for loop ending then execute the User_UidSearch,

but how can I slove the it "i" is 0 and 1.

6
  • No, it's not. It's defined in outer function local scope. But it's used in closure, which needs special logic to work. @Salmon - are you sure console.log(i) writes undefined and not the value of results.length? Commented Aug 13, 2014 at 7:55
  • @BOSS I would love to see a fiddle demonstrating that. Commented Aug 13, 2014 at 7:56
  • 1
    "Outputs are 'undefined' of all" doesn't really fit with the snippet provided. i should at least be a number, just maybe not the particular values expected. If each log shows the value of results.length, then see: JavaScript closure inside loops – simple practical example. Commented Aug 13, 2014 at 7:56
  • wrap the user_UidSearch call in a closure, pass in i and results Commented Aug 13, 2014 at 7:57
  • @IlyaLuzyanin: rigt.my bad i didnt see it through clearly.removed my comment Commented Aug 13, 2014 at 7:58

2 Answers 2

3

Your problem may be solved, but let me still add these points so others know the correct approach.

Firstly, its not a good practice to call an asynchronous function inside a loop. This would lead to unexpected results.

Using closures is fine for some cases, but not this one. Read here for Practical uses of closures.

There are several problems in the approach you've taken,

  1. If the results array is too long, there'll be a too many open requests.
  2. callback(results) will be called before even a single callback of User_UidSearch is called.

In your case, you should be using recursive function like this:

var len = results.length;
var count = 0;
function my_func() {
    User_UidSearch(results[count].employee, function (user) {
        console.log(count);
        // results[count]['email'] = user.email;

        count += 1;
        if (count < len) {
            my_func();
        } else {
            callback(results);
        }
    });
}

Read this if interested detailed explaination of different control flows.

Sign up to request clarification or add additional context in comments.

1 Comment

Yes, you're right. I had solved your saying. But your solution is better than mine, thank you very much :)
1

You're dealing with closures, rewrite your code as follows:

...
(function(id) {
    User_UidSearch(results[id].employee, function (user) {
        console.log(id);
        // results[i]['email'] = user.email;
    });
})(i);

I.e. wrap your function to unbind i.

2 Comments

Thank you very much, I follow this way solving.
You're welcome! Closures are great stuff if you know how to use them right!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.