Good time of day! I recently started learning JavaScript and I'm having some difficulty with asynchronous requests. I have to do a lot of requests to the server in as a short time as possible.
for (i=0;i<10;i++;) {
method.call(get, data: "id", function(result) {
id = id.concat(data.id);
})
}
I think my way is incorrect since the request can not be processed in time and has the risk of not getting part of the information.
If you understand what I mean, is there a universal method that is used in such cases and are there any links to articles where all details of working with asynchrony and emerging issues are explained? Sorry for the long question.
4 Answers 4
If timing doesn't matter, you want to use a concept called promises. http://www.promisejs.org/intro/ and http://blogs.msdn.com/b/ie/archive/2011/09/11/asynchronous-programming-in-javascript-with-promises.aspx are good intros. In pseudo code:
when(somethinghappens).then(dosomething)
You can set 10 of those to execute and they will not block each other, presuming the browser allows that many connections.
If timing matters (B can't happen until A is completed) then you want to use callbacks.
getstuff(thingA, function(){
// do stuff with thingA and then:
getStuff(thingB, function(){
// do stuff with thingB and then:
getStfuff(thingC, function
// and so on
}
}
}
Of course, callbacks don't need to be a nested hell of anonymous function calls. You can name each and do the next call back within the function.
getstuff(thingA, doCallBackB);
function doCallBackB (stuffFromThingA) {
// do stuff with stuffFromThingA and then
getstuff(thingB, doCallBackC);
}
More on Callbacks:
Comments
This code will provide some kind of async recursive loop:
function getId(i) {
method.call(get, data: "id", function(result) {
id = id.concat(data.id);
if (i < 10) {
i++;
getId(i);
}
});
}
var id = "";
getId(0);
You pass the counter i on each call and check if its reached the limit before call getId another time. So that way the loop will only iterate to next step after each request callback.
Its a kind of pseudo-code, I didn't tested but this is the logic.
Comments
I came up with this solution, with a logic seperated approach. I call it async loop, the asyncLoop function here is the main part which is completely general but to use it you should create a function with a specific signature (for the logic code), a function with only one single argument as a callback:
var id="";
function getId(callback){
method.call(get, {data: "id"}, function(result) {
id = id.concat(data.id);
callback();
});
}
function asyncLoop(i, len, asyncCall) {
if(i < len){
asyncCall(function(){
asyncLoop(i++, len, asyncCall);
});
}
}
asyncLoop(0, 10, getId);
The point is, this is not the only way to do this, but what I like about this solution is its general view.
Comments
A nice technology for dealing with this kind of asynchronous looping is called continuation programming style (CPS). CPS is closely related to a technology called coroutines. The answer by Will suggests using callbacks, and that is closely related to how CPS is implemented in JavaScript. There are many articles on implementing CPS in JavaScript; here are a few good ones:
- Continuation-Passing Style and why JavaScript developers might be interested in it by Marijn Haverbeke
- By example: Continuation-passing style in JavaScript by Matt Might
- Asynchronous programming and continuation-passing style in JavaScript by Axel Rauschmayer
The basic idea of CPS is to apply two ideas:
- Never return a value from a function; instead write the function to take another function (the continuation) as an extra argument and at the place where a value would be returned, instead call the continuation, passing the return value as an argument.
- Whenever function A calls another function B, that's the last thing that A does. If more work is needed, pass a continuation to B that encapsulates the remaining work. When B is done it will call the continuation and the work will then get done.
Sometimes one more idea is added when implementing CPS in JavaScript: use setTimeout() to call the continuation; this avoids stack overflow due to excessive layers of function calls. (Other approaches are also possible to deal with this issue.) The above articles (and many more that you can find with a simple search) elaborate the above ideas and provide lots of examples, including asynchronous looping, AJAX, and many other applications.
method.call(get, data: "id", function(result) { id = id.concat(data.id); })this is not valid js syntax