简体   繁体   中英

task.js generators/promises vs. async callbacks

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.

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

gumballhead recommended async.js , but i would recommend using Parse Cloud Code if you're working with Node. Their API has promises built right in, along with other goodies (like a database). It saves time and you don't have to worry about backend stability. You can include any NPM module with a little tweak of module.exports to just exports . It also integrates seamlessly with your frontend! I've been having success with this approach on my current project and just wanted to comment with a new approach.

Feel free to comment with any reasons why/when you should not use Cloud Code; for I have had no such experience yet.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM