admin管理员组

文章数量:1415645

I have a list of tasks that I want to run in parallel using .

I want the program to proceed (probably through a callback) after the first of these parallel tasks is plete, not all of them. So I don't think the naive

async.parallel([task1, task2], callback)

works for me.

Alternatively I could spawn two tasks and cancel the inplete one, but I can't figure out how to do that using async either.

Thanks! -Charlie

I have a list of tasks that I want to run in parallel using https://github./caolan/async.

I want the program to proceed (probably through a callback) after the first of these parallel tasks is plete, not all of them. So I don't think the naive

async.parallel([task1, task2], callback)

works for me.

Alternatively I could spawn two tasks and cancel the inplete one, but I can't figure out how to do that using async either.

Thanks! -Charlie

Share Improve this question asked Jun 1, 2013 at 2:00 Charles OffenbacherCharles Offenbacher 3,1323 gold badges33 silver badges38 bronze badges 2
  • 1 async cannot cancel a task once it's started it; after that, it can only wait for it to finish or ignore it. The ability to cancel would have to reside with the task or the object that owns it. Something akin to XMLHttpRequest's .abort(). – Jonathan Lonowski Commented Jun 1, 2013 at 3:28
  • That fact means I have to try a different approach - thanks for the info! – Charles Offenbacher Commented Jun 1, 2013 at 4:22
Add a ment  | 

2 Answers 2

Reset to default 6

Parallel Race

You can get async to initiate the final callback by returning an error that evaluates as true but isn't actually an error.

I've put together an example that uses -1 as an error code. In the final callback I check the error value and if it's not -1 then it's an actual error. If the error value is -1 then we'll have a valid value in results. At that point, we just need to remove extra elements from results of the other async functions that have not pleted yet.

In the below example I've used the request module to pull html pages and the underscore module to filter the results in the final callback.

var request = require('request');
var _ = require('underscore');

exports.parallel = function(req, res) {
  async.parallel([
    /* Grab Google.jp */
    function(callback) {
      request("http://google.jp", function(err, response, body) {
        if(err) { console.log(err); callback(true); return; }
        callback(-1,"google.jp");
      });
    },
    /* Grab Google. */
    function(callback) {
      request("http://google.", function(err, response, body) {
        if(err) { console.log(err); callback(true); return; }
        callback(-1,"google.");
      });
    }
    ],
    /* callback handler */
    function(err, results) {
      /* Actual error */
      if(err && err!=-1) {
        console.log(err);
        return;
      }
      /* First data */
      if(err===-1) {
        /*
         * async#parallel returns a list, one element per parallel function.
         * Functions that haven't finished yet are in the list as undefined.
         * use underscore to easily filter the one result.
         */
        var one = _.filter(results, function(x) {
          return (x===undefined ? false : true);
        })[0];
        console.log(results);
        console.log(one);
        res.send(one);
      }
    }
  );
};

Remaining Function Results

When you setup async#parallel to work like this you won't have access to the results of the other asynchronous functions. If you're only interested in the first one to respond then this isn't a problem. However, you will not be able to cancel the other requests. That's most likely not a problem, but it might be a consideration.

The async.parallel documentation says:

If any of the functions pass an error to its callback, the main callback is immediately called with the value of the error.

So you could return an error object from all of your parallel functors, and the first one to finish would jump you to the pletion callback. Perhaps even your own special error class, so you can tell the difference between an actual error and a "hey I won" error.

Having said that, you would still have your parallel functions running, potentially waiting for callbacks to plete or whatever. Perhaps you could use async.parallelLimit to make sure you're not firing off too many tasks in parallel ?

Having said all that, it's possible you are better served by trying another method from the async library for this task - firing off parallel tasks then having these tasks race each other may not be the best idea.

本文标签: javascriptHow to end on first async parallel task completion in NodeStack Overflow