Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JavaScript async callback and scope

Consider the following example:

var cb = function (t) {
    console.log('callback -->' + t);
};

for(var i = 0; i<3; i++) {
    console.log(i);
    setTimeout(function(){
        cb(i);
    },1000);
}

Working example at jsfiddle

The output of this code snippet is:

0
1
2
callback ---> 3
callback ---> 3
callback ---> 3

Everything works as expected, for loop puts 3 callback calls into the event loop. By the end of the for loop i == 3 and when the callbacks get executed all of them print 3 because they contain the link to the i which is 3. How could this snippet be improved so when the callback gets executed it uses the actual value which was passed to it.

The output should be:

callback ---> 1
callback ---> 2
callback ---> 3

Thanks in advance.

like image 464
Igor Malyk Avatar asked Apr 29 '13 09:04

Igor Malyk


People also ask

Can we use async in callback?

A callback is just a function that's passed into another function, with the expectation that the callback will be called at the appropriate time. As we just saw, callbacks used to be the main way asynchronous functions were implemented in JavaScript.

What is the scope of a callback function in JavaScript?

The callback function, like any JavaScript function, will have access to the context where it was declared in. If the callback function is an inner function, it is a closure that is able to access variables in the outer function. As was shown above, closures can be used to maintain private state.

What is the difference between callback and async await?

Await eliminates the use of callbacks in . then() and . catch(). In using async and await, async is prepended when returning a promise, await is prepended when calling a promise.

Are all callbacks asynchronous in JavaScript?

Callbacks that you call yourself are regular function calls, which are always synchronous. Certain native APIs (eg, AJAX, geolocation, Node. js disk or network APIs) are asynchronous and will execute their callbacks later in the event loop.


2 Answers

You could try .bind:

for(var i = 0; i<3; i++) {
    console.log(i);
    setTimeout(cb.bind(null, i),1000);
}

The demo.

The traditional way to handle this is to create a closure:

for(var i = 0; i<3; i++) {
    console.log(i);
    setTimeout((function(i){return function(){cb(i)}}(i)),1000);
}
like image 180
xdazz Avatar answered Sep 21 '22 11:09

xdazz


A frequent question. Let's try to use some features of future of JS. I mean let. It creates local scope variable and you don't need to use a closure or another trick. But now it works only in FF (i'm using 20.0.1)

for(var i = 0; i<3; i++) {
    console.log(i);
    let a = i;
    setTimeout(function(){               
        cb(a);
    },1000);
}
like image 40
Damask Avatar answered Sep 19 '22 11:09

Damask