Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

some and every should short-circuit #125

Closed
mvolkmann opened this Issue · 4 comments

4 participants

@mvolkmann

The some and every functions in async don't short-circuit like their counterparts in JavaScript (ES5) and Underscore.js do. The iterator function is executed on every element in the array instead of stopping once the boolean result of some or every is known. I understand that the result is passed to the callback as soon as it is known, but I think it's wrong for the remaining elements to be passed to the iterator. That can cause unintended side effects.

The code below demonstrates this:

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

function isPositive(num) {
  console.log('num =', num);
  return num > 0;
}

function isPositiveAsync(num, cb) {
  var result = isPositive(num);
  console.log('result =', result);
  cb(result);
}

var arr = [-1, 0, 1, 2];

console.log('JavaScript');
console.log(arr.some(isPositive));

console.log('\nUnderscore');
console.log(_.some(arr, isPositive));

console.log('\nAsync');
async.some(arr, isPositiveAsync, function (result) {
  console.log('final =', result);
});
console.log('Why was 2 evaluated by async.some?');

Here is the output:

JavaScript
num = -1
num = 0
num = 1
true

Underscore
num = -1
num = 0
num = 1
true

Async
num = -1
result = false
num = 0
result = false
num = 1
result = true
final = true
num = 2
result = true
Why was 2 evaluated by async.some?
@mvolkmann

Okay, I've been straightened out on this. There's a good reason why async.some and async.every work they way they do. However, I think there is also a need for new functions named someSeries and everySeries that evaluate the elements in the array one at a time and stop as soon as the result is known. So consider this a feature request to add those functions.

@mkoistinen

First, it isn't clear to me why you would require BOTH a short-circuiting version of some and every. It seems that a short-circuiting version of some() would simply be the logical inverse of a short-circuiting every(). What am I missing?

Regardless, doesn't detect() and its serial companion detectSeries() fit the bill nicely? Its working for me, short-circuiting once a condition is 'detected'. I also use them as 'any()' or 'anySeries()' (both fictitious) by reversing the condition. Again, am I missing something here?

@mvolkmann

You are correct that having a short-circuiting version of both some and every isn't required. You could say that same about needing the current version of both some and every. It is convenient to have both, but not required.

We could replace every use of some and every with detect. However, they are logically different. I don't want to use detect unless I really want to do something with the value that it returns. If I only want to know if a certain kind of value exists, some and every communicate that better.

@caolan caolan closed this
@alizbazar
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.