I want to know which of the two methods are better when dealing with asynchronous code in JavaScript. I want to understand which method leads to cleaner code. I'm used with promises and they seem more flexible than the async approach (https://github.com/caolan/async).
I also know about the Task.js library (http://taskjs.org/), but this relies on the yield keyword which is part of Ecmascript Harmony.
They can handle multiple asynchronous operations easily and provide better error handling than callbacks and events. In other words also, we may say that, promises are the ideal choice for handling multiple callbacks at the same time, thus avoiding the undesired callback hell situation.
Async/Await is used to work with promises in asynchronous functions. It is basically syntactic sugar for promises. It is just a wrapper to restyle code and make promises easier to read and use. It makes asynchronous code look more like synchronous/procedural code, which is easier to understand.
A callback function is passed as an argument to another function whereas Promise is something that is achieved or completed in the future. In JavaScript, a promise is an object and we use the promise constructor to initialize a promise.
In this article I will apply those concepts and show how we can use generators to build something similar to async/await. In fact, async/await is implemented using generators and promises.
The async
library encapsulates a couple of very common asynchronous patterns, including making arbitrary async calls in parallel and iterating over a list asynchronously. It's designed to work with "nodeback" (err, res)
APIs, which makes it useful for a lot of Node.js applications. async
is however a specific solution, and it only simplifies the async patterns included in the library.
Promises, by contrast, are in my opinion a much more general solution to the problem of asynchronous code. Not only do they provide the obvious benefits at first glance of error-bubbling and of flattening callback pyramids, problems that would otherwise require the sorts of complex patterns async
encapsulates can be solved much more simply.
I'll demonstrate this with a quick tour through some of async
's available patterns. For instance, the async.waterfall
function is used something like this:
async.waterfall([
function (cb) {
asyncCall('argument', cb);
},
function(resultOfFirstCall, cb) {
anotherCall(resultOfFirstCall, 'someOtherArgument' cb);
},
], function(err, res) {
if (err) handle(err);
useFinalResult(res);
});
There's no equivalent to async.waterfall
in most promise libraries (or at least there isn't one in Q), because it's so simple to implement it from scratch using Array.reduce
, like so (example based on Q but pretty much the same on other promise libraries):
[
function() {
return asyncCall('argument');
},
function(resultOfFirstCall) {
return anotherCall(resultOfFirstCall, 'someOtherArgument');
}
].reduce(Q.when, Q())
.then(useFinalResult, handle);
The other big functions in async
include async.parallel
, which Q includes as Q.all
:
// async
async.parallel([
asyncFunc,
asyncFunc2
], function(err, res) {
if (err) handle(err);
useFinalResult(res);
// res[0] === asyncFuncResult
// res[1] === asyncFunc2Result
});
// Q
Q.all([
asyncFunc(),
asyncFunc2()
]).then(useFinalResult, handle);
And async.map
. You actually don't need async.map
when you're using promises, because the normal Array.map
is sufficient:
// async
async.map(['file', 'file2', 'file3'], fs.stat, function(err, res) {
if (err) handle(err);
useFinalResult(res);
});
// Q
Q.all(['file', 'file2', 'file3']
.map(Q.nfbind(fs.stat)))
.then(useFinalResult, handle);
The rest of async
is similarly easy to implement concisely, using relatively simple pieces of your promise library. (Note that that last example used a function Q.nfbind
: nfbind
and the other nf*
functions Q provides are basically all you need to use promises with nodeback APIs, so there isn't even a particularly big impedance trying to use promises with libraries that expect nodebacks.)
In the end, whether you use promises or nodebacks is up to you, but I think promises are a much more flexible, capable, and generally concise way to implement most all asynchronous operations.
Callbacks are imperative, promises are functional is worth a read for more information in this general vein.
Since you tagged your question with node, I'd recommend the async library. The control flow functions are great to work with and eliminate the ugly and hard to follow callback chains. The API is setup really nice for injecting callbacks that follow node's signature (error, result)
into the control functions. It's basically included by default in almost all node scripts I write.
While you can use async for client-side as well, it's probably unnecessary for most projects. jQuery includes promises, and you can accomplish the same thing with them.
I think promise/a and async lib with difference targets, promise focus on one step async operation progress, and async focus on multi step async operate, for node, async has a wilder use for a lot of async apis.
by the way, to deal with async operations, use named function instead of Anonymous functions will be the most effective way
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With