It's highly unlikely that you can achieve with plain js the same level of conciseness and expressiveness in working with callbacks that C# 5 has. The compiler does the work in writing all that boilerplate for you, and until the js runtimes will do that, you will still have to pass an occasional callback here and there.
However, you may not always want to bring callbacks down to the level of simplicity of linear code - throwing functions around doesn't have to be ugly, there's an entire world working with this kind of code, and they keep sane without async
and await
.
For instance, use higher-order functions (my js may be a bit rusty):
// generic - this is a library function
function iterateAsync(iterator, action, onSuccess, onFailure) {
var item = iterator();
if(item == null) { // exit condition
onSuccess();
return;
}
action(item,
function (success) {
if(success)
iterateAsync(iterator, action, onSuccess, onFailure);
else
onFailure();
});
}
// calling code
var currentImage = 0;
var imageCount = 42;
// you know your library function expects an iterator with no params,
// and an async action with the current item and its continuation as params
iterateAsync(
// this is your iterator
function () {
if(currentImage >= imageCount)
return null;
return "http://my/server/GetImage?" + (currentImage++);
},
// this is your action - coincidentally, no adaptor for the correct signature is necessary
LoadImageAsync,
// these are your outs
function () { console.log("All OK."); },
function () { console.log("FAILED!"); }
);
Since what you are really talking about here is a stylistic/readability issue (at least, that's the way I read it), you might be a little out of luck, because all the all alteratives I can think of aren't great.
Really you have two options, write multiple distinct functions like you have done above, or use closures to bring it all "inline" (as it were), where you will quickly run into issues with keeping the horizontal whitespace sane.
That being said, if you really do want to keep it all in a single block that looks like one procedure, I would probably go with the closure option:
function(){
command1;
var x1 = something;
async_function(x1, function (data){
var x2 = command2(data);
async_function2(x2, function (data1){
command3(data1);
});
});
}
Which could of course be spaced out like this, quite close to your desired example:
function(){
command1;
var x1 = something;
async_function(x1, function (data){
var x2 = command2(data);
async_function2(x2, function (data1){
command3(data1);
});});
}
...but personally I would probably try and stick to the first version.
In general though I wouldn't do either. I would keep it broken down into small and obviously named routines, I find it makes for much more readable code in the long run and any sane IDE will allow you to jump from function call to function definition and vice versa, so navigation shouldn't be too much of an issue.
Best Answer
It doesn't. Just taking a callback or passing a callback doesn't mean it's asynchronous.
For example, the
.forEach
function takes a callback but is synchronous.The
setTimeout
takes a callback too and is asynchronous.Hooking to any asynchronous event in Javascript always requires a callback but that doesn't mean calling functions or passing them around is always asynchronous.