Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

async.race = execute in parallel, but only use the first result #568

Closed
rprieto opened this issue Jul 2, 2014 · 16 comments
Closed

async.race = execute in parallel, but only use the first result #568

rprieto opened this issue Jul 2, 2014 · 16 comments
Labels
Milestone

Comments

@rprieto
Copy link

rprieto commented Jul 2, 2014

I found myself needing this type of function a few times:

  • execute several async operations in parallel
  • call done whenever the first one finished, and ignore any subsequent results

It's easily implemented as follows, but does it belong in async? Happy to submit a PR with unit tests.

async.first = function(ops, done) {
  var i = 0;
  var response = false;
  for (i = 0; i < ops.length; ++i) {
    ops[i](function(err, data) {
      if (!response) {
        response = true;
        done(err, data);
      }
    });
  }
};
@fritx
Copy link
Contributor

fritx commented Jul 3, 2014

async.any ?

@rprieto
Copy link
Author

rprieto commented Jul 3, 2014

The way I understand async.any is is runs the same asynchronous predicate on multiple items, and calls the callback with true or false (depending if any items matched).

In my case I'd like to run several (different) async functions, and return the result of the first one to finish.
For example:

// we have potential services that can return the same data
// call both in parallel and return whichever comes back first
async.first([
  getDataFromServiceX,
  getDataFromServiceY
], done);

or

// call done() when the long operation finishes
// or after 1 sec, whichever happens first
async.first([
  function(next) { longRunningOperation(next); }
  function(next) { setTimeout(next, 1000);     }
], done);

@fritx
Copy link
Contributor

fritx commented Jul 3, 2014

Yeah, I was wrong.. Haha

@rprieto
Copy link
Author

rprieto commented Jul 3, 2014

No worries :)

@vaiwa
Copy link

vaiwa commented Sep 4, 2014

I would like this feature too =)

Now I hacked async.parralel so that it returns data in err and err in data, but it is really ugly and confusing.

@kumavis
Copy link

kumavis commented Jun 7, 2015

+1 do want

@kumavis
Copy link

kumavis commented Jun 7, 2015

an alternate mode would be to ignore errors, and keep waiting for the first non-failure response, until all have been attempted

@ORESoftware
Copy link
Contributor

+1

@ORESoftware
Copy link
Contributor

@rprieto you might need to create some logic to check the result of the request. for example, if the request returns an error, we might not want the first one, or if the first request doesn't have the data you want, you might not want the first result either. So there might need to be some conditional check in there somewhere.

So for generic usage, we want not just the first result but the first result that meets some condition. So your version of async.first might want to take one more argument in the form of a function that contains some conditional logic that returns a boolean.

@ORESoftware
Copy link
Contributor

something that looks like:

async.first = function(ops, func, done) {  // developer defined func to check condition
  var length = ops.length;
  var responses = 0;
  var success = false;
  for (var i = 0; i < length; i++) {
    ops[i](function(err, data) {
      responses++;
      if (!success) {
        if(func(err,data)){  
          success = true;
          done(err, data);
          }
          else if(responses >= length){  //we have received all responses, but none met the condition
          success = true;   // probably should rename success var, but ok for now
          done(new Error('all responses received, but no responses met condition'), data);
          }
         else{
           //do nothing, wait for the next response
         }
      }
    });
  }
};

@ORESoftware
Copy link
Contributor

so that might look like this in action:

async.first([], function(err,data){
    if(err){
          return false;
      }
      else if(data.error){
         return false;
     }
      else{
         return true;
    }
}, function done(err, data){
      // do your thing
});

@aearly
Copy link
Collaborator

aearly commented Sep 28, 2015

I think async.race is a good name for this -- it has some symmetry with Promise.race

@ORESoftware
Copy link
Contributor

I thought about that name too (or maybe some other mention of race seeded my thought process)

@moeriki
Copy link

moeriki commented Oct 30, 2015

I implemented an asyncOneOf / asyncOneOfParallel because I liked this as well.

https://gist.github.com/Moeriki/4d5053052d1302f08d98

@aearly aearly changed the title async.first = execute in parallel, but only use the first result async.race = execute in parallel, but only use the first result Jan 7, 2016
@aearly aearly added this to the 2.0 milestone Feb 27, 2016
@aearly
Copy link
Collaborator

aearly commented Feb 27, 2016

Closed by #1038 !

@aearly aearly closed this as completed Feb 27, 2016
@kumavis
Copy link

kumavis commented Feb 28, 2016

😸 👏

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

7 participants