Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Calling an asynchronous function within a for loop in JavaScript

I have the following code:

for(var i = 0; i < list.length; i++){     mc_cli.get(list[i], function(err, response) {         do_something(i);     }); } 

mc_cli is a connection to a memcached database. As you can imagine, the callback function is asynchronous, thus it may be executed when the for loop already ended. Also, when calling in this way do_something(i) it always uses the last value of the for loop.

I tried with a closure in this way

do_something((function(x){return x})(i))  

but apparently this is again using always the last value of the index of the for loop.

I also tried declaring a function before the for loop like so:

var create_closure = function(i) {     return function() {         return i;     } } 

and then calling

do_something(create_closure(i)()) 

but again without success, with the return value always being the last value of the for loop.

Can anybody tell me what am I doing wrong with closures? I thought I understood them but I can't figure why this is not working.

like image 618
Masiar Avatar asked Nov 12 '12 12:11

Masiar


People also ask

Can we use async in for loop?

Combining async with a for (or a for...of ) loop is possibly the most straightforward option when performing asynchronous operations over array elements. Using await inside a for loop will cause the code to stop and wait for the asynchronous operation to complete before continuing.

How do I run async await in for loop?

You can use a for-of loop or a for/while loop, it doesn't really matter which one you pick. (async() => { data = [1, 2, 3, 4, 5]; for (let e of data) { const i = await somePromiseFn(e); console. log(i); } console.

Is it possible to run an asynchronous code in JavaScript?

JavaScript is a single-threaded, non-blocking, asynchronous, concurrent programming language with lots of flexibility.

How does JavaScript handle asynchronous calls?

JavaScript provides three methods of handling asynchronous code: callbacks, which allow you to provide functions to call once the asynchronous method has finished running; promises, which allow you to chain methods together; and async/await keywords, which are just some syntactic sugar over promises.


2 Answers

Since you're running through an array, you can simply use forEach which provides the list item, and the index in the callback. Iteration will have its own scope.

list.forEach(function(listItem, index){   mc_cli.get(listItem, function(err, response) {     do_something(index);   }); }); 
like image 154
Joseph Avatar answered Oct 08 '22 06:10

Joseph


This is the asynchronous-function-inside-a-loop paradigm, and I usually deal with it using an immediately-invoked-anonymous-function. This ensures that the asynchronous functions get called with the correct value of the index variable.

Okay, great. So all the asynchronous functions have been started up, and the loop exits. Now, there is no telling when these functions will complete, due to their asynchronous nature, or in what order they will complete. If you have code that needs to wait until all these functions have completed before executing, I recommend keeping a simple count of how many functions have finished:

var total = parsed_result.list.length; var count = 0;  for(var i = 0; i < total; i++){     (function(foo){         mc_cli.get(parsed_result.list[foo], function(err, response) {             do_something(foo);             count++;             if (count > total - 1) done();         });     }(i)); }  // You can guarantee that this function will not be called until ALL of the // asynchronous functions have completed. function done() {     console.log('All data has been loaded :).'); } 
like image 32
user3707766 Avatar answered Oct 08 '22 06:10

user3707766