From 0ed159afd094ff1446fce6d616064f9c31fb7d2a Mon Sep 17 00:00:00 2001 From: Graeme Yeates Date: Thu, 2 Jul 2015 10:49:31 -0400 Subject: Share the implementation of some and every --- lib/async.js | 50 ++++++++++++++++++++++++-------------------------- package.json | 2 +- 2 files changed, 25 insertions(+), 27 deletions(-) diff --git a/lib/async.js b/lib/async.js index 67eb379..8b467eb 100644 --- a/lib/async.js +++ b/lib/async.js @@ -9,6 +9,12 @@ var async = {}; function noop() {} + function identity(v) { + return v; + } + function notId(v) { + return !v; + } // global on the server, window in the browser var previous_async; @@ -449,35 +455,27 @@ async.detect = doParallel(_detect); async.detectSeries = doSeries(_detect); - async.any = - async.some = function (arr, iterator, main_callback) { - async.eachOf(arr, function (x, _, callback) { - iterator(x, function (v) { - if (v) { - main_callback(true); - main_callback = noop; - } - callback(); + function _createTester(eachfn, check, defaultValue) { + return function(arr, iterator, main_callback) { + eachfn(arr, function (x, _, callback) { + iterator(x, function (v) { + if (check(v)) { + main_callback(!defaultValue); + main_callback = noop; + } + callback(); + }); + }, function () { + main_callback(defaultValue); }); - }, function () { - main_callback(false); - }); - }; + }; + } + + async.any = + async.some = _createTester(async.eachOf, identity, false); async.all = - async.every = function (arr, iterator, main_callback) { - async.eachOf(arr, function (x, _, callback) { - iterator(x, function (v) { - if (!v) { - main_callback(false); - main_callback = noop; - } - callback(); - }); - }, function () { - main_callback(true); - }); - }; + async.every = _createTester(async.eachOf, notId, true); async.sortBy = function (arr, iterator, callback) { async.map(arr, function (x, callback) { diff --git a/package.json b/package.json index e26d3c6..fb4b581 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "description": "Higher-order functions and common patterns for asynchronous code", "main": "lib/async.js", "author": "Caolan McMahon", - "version": "1.3.0", + "version": "1.2.1", "keywords": [ "async", "callback", -- cgit v1.2.1 From 06813bffd737a183d01e0fa89d70a31635019676 Mon Sep 17 00:00:00 2001 From: mtone Date: Mon, 9 Jun 2014 21:37:49 -0400 Subject: Added async.someLimit When checking if a folder contains subfolders or not (fs.readdir -> fs.stat -> some(is_a_Folder)), getting crashes when listing Windows shares from Ubuntu VM. someLimit avoids the problem. Test for someLimit added anyLimit alias and updated doc. removed anyLimit alias --- README.md | 28 ++++++++++++++++++++++++++-- lib/async.js | 20 +++++++++++++++----- test/test-async.js | 18 ++++++++++++++++++ 3 files changed, 59 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index d50da34..e09b22b 100644 --- a/README.md +++ b/README.md @@ -172,8 +172,11 @@ Some functions are also available in the following forms: * [`reduce`](#reduce), [`reduceRight`](#reduceRight) * [`detect`](#detect), `detectSeries` * [`sortBy`](#sortBy) -* [`some`](#some), [`every`](#every) -* [`concat`](#concat), `concatSeries` +* [`some`](#some) +* [`someLimit`](#someLimit) +* [`every`](#every) +* [`concat`](#concat) +* [`concatSeries`](#concatSeries) ### Control Flow @@ -581,6 +584,27 @@ async.some(['file1','file2','file3'], fs.exists, function(result){ --------------------------------------- + +### someLimit(arr, limit iterator, callback) + +__Alias:__ `anyLimit` + +The same as [`some`](#some), only no more than `limit` `iterator`s will be simultaneously +running at any time. + +__Arguments__ + +* `arr` - An array to iterate over. +* `limit` - The maximum number of `iterator`s to run at any time. +* `iterator(item, callback)` - A truth test to apply to each item in the array + in parallel. The iterator is passed a callback(truthValue) which must be + called with a boolean argument once it has completed. +* `callback(result)` - A callback which is called as soon as any iterator returns + `true`, or after all the iterator functions have finished. Result will be + either `true` or `false` depending on the values of the async tests. + +--------------------------------------- + ### every(arr, iterator, [callback]) diff --git a/lib/async.js b/lib/async.js index 8b467eb..f0e3adf 100644 --- a/lib/async.js +++ b/lib/async.js @@ -456,8 +456,11 @@ async.detectSeries = doSeries(_detect); function _createTester(eachfn, check, defaultValue) { - return function(arr, iterator, main_callback) { - eachfn(arr, function (x, _, callback) { + return function(arr, limit, iterator, main_callback) { + function done() { + main_callback(defaultValue); + } + function iteratee(x, _, callback) { iterator(x, function (v) { if (check(v)) { main_callback(!defaultValue); @@ -465,15 +468,22 @@ } callback(); }); - }, function () { - main_callback(defaultValue); - }); + } + if (arguments.length > 3) { + eachfn(arr, limit, iteratee, done); + } else { + main_callback = iterator; + iterator = limit; + eachfn(arr, iteratee, done); + } }; } async.any = async.some = _createTester(async.eachOf, identity, false); + async.someLimit = _createTester(async.eachOfLimit, identity, false); + async.all = async.every = _createTester(async.eachOf, notId, true); diff --git a/test/test-async.js b/test/test-async.js index 25e964e..fe94ddc 100755 --- a/test/test-async.js +++ b/test/test-async.js @@ -2236,6 +2236,24 @@ exports['some early return'] = function(test){ }, 100); }; +exports['someLimit true'] = function(test){ + async.someLimit([3,1,2], 2, function(x, callback){ + setTimeout(function(){callback(x === 2);}, 0); + }, function(result){ + test.equals(result, true); + test.done(); + }); +}; + +exports['someLimit false'] = function(test){ + async.someLimit([3,1,2], 2, function(x, callback){ + setTimeout(function(){callback(x === 10);}, 0); + }, function(result){ + test.equals(result, false); + test.done(); + }); +}; + exports['any alias'] = function(test){ test.equals(async.any, async.some); test.done(); -- cgit v1.2.1 From c61e63b357262f627d945bd0f41aeaa02b95c361 Mon Sep 17 00:00:00 2001 From: Graeme Yeates Date: Thu, 2 Jul 2015 11:28:52 -0400 Subject: Add everyLimit --- lib/async.js | 2 ++ test/test-async.js | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/lib/async.js b/lib/async.js index f0e3adf..a914542 100644 --- a/lib/async.js +++ b/lib/async.js @@ -487,6 +487,8 @@ async.all = async.every = _createTester(async.eachOf, notId, true); + async.everyLimit = _createTester(async.eachOfLimit, notId, true); + async.sortBy = function (arr, iterator, callback) { async.map(arr, function (x, callback) { iterator(x, function (err, criteria) { diff --git a/test/test-async.js b/test/test-async.js index fe94ddc..b7847bf 100755 --- a/test/test-async.js +++ b/test/test-async.js @@ -2254,6 +2254,24 @@ exports['someLimit false'] = function(test){ }); }; +exports['every true'] = function(test){ + async.everyLimit([3,1,2], 1, function(x, callback){ + setTimeout(function(){callback(x > 1);}, 0); + }, function(result){ + test.equals(result, true); + test.done(); + }); +}; + +exports['everyLimit false'] = function(test){ + async.everyLimit([3,1,2], 2, function(x, callback){ + setTimeout(function(){callback(x === 2);}, 0); + }, function(result){ + test.equals(result, false); + test.done(); + }); +}; + exports['any alias'] = function(test){ test.equals(async.any, async.some); test.done(); -- cgit v1.2.1 From 84eb0fe61c74479839f9494ba96a7ea235d4812e Mon Sep 17 00:00:00 2001 From: Graeme Yeates Date: Thu, 2 Jul 2015 11:32:14 -0400 Subject: Partial short circuit for some* and every* --- lib/async.js | 13 +++++++------ package.json | 2 +- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/lib/async.js b/lib/async.js index a914542..68317d4 100644 --- a/lib/async.js +++ b/lib/async.js @@ -456,15 +456,16 @@ async.detectSeries = doSeries(_detect); function _createTester(eachfn, check, defaultValue) { - return function(arr, limit, iterator, main_callback) { + return function(arr, limit, iterator, cb) { function done() { - main_callback(defaultValue); + if (cb) cb(defaultValue); } function iteratee(x, _, callback) { + if (!cb) return callback(); iterator(x, function (v) { - if (check(v)) { - main_callback(!defaultValue); - main_callback = noop; + if (cb && check(v)) { + cb(!defaultValue); + cb = false; } callback(); }); @@ -472,7 +473,7 @@ if (arguments.length > 3) { eachfn(arr, limit, iteratee, done); } else { - main_callback = iterator; + cb = iterator; iterator = limit; eachfn(arr, iteratee, done); } diff --git a/package.json b/package.json index fb4b581..e26d3c6 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "description": "Higher-order functions and common patterns for asynchronous code", "main": "lib/async.js", "author": "Caolan McMahon", - "version": "1.2.1", + "version": "1.3.0", "keywords": [ "async", "callback", -- cgit v1.2.1 From 3c900be947697d00eb6fdb0f57c205825a652a5a Mon Sep 17 00:00:00 2001 From: Graeme Yeates Date: Thu, 2 Jul 2015 12:58:01 -0400 Subject: Add benchmarks for some and every --- lib/async.js | 2 +- perf/suites.js | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/lib/async.js b/lib/async.js index 68317d4..ed47c57 100644 --- a/lib/async.js +++ b/lib/async.js @@ -465,7 +465,7 @@ iterator(x, function (v) { if (cb && check(v)) { cb(!defaultValue); - cb = false; + cb = iterator = false; } callback(); }); diff --git a/perf/suites.js b/perf/suites.js index b4ea76b..42611db 100644 --- a/perf/suites.js +++ b/perf/suites.js @@ -179,6 +179,66 @@ module.exports = [ } } }, + { + name: "some - no short circuit- false", + // args lists are passed to the setup function + args: [[500]], + setup: function(count) { + tasks = _.range(count); + }, + fn: function (async, done) { + async.some(tasks, function(i, cb) { + async.setImmediate(function() { + cb(i >= 600); + }); + }, done); + } + }, + { + name: "some - short circuit - true", + // args lists are passed to the setup function + args: [[500]], + setup: function(count) { + tasks = _.range(count); + }, + fn: function (async, done) { + async.some(tasks, function(i, cb) { + async.setImmediate(function() { + cb(i >= 60); + }); + }, done); + } + }, + { + name: "every - no short circuit- true", + // args lists are passed to the setup function + args: [[500]], + setup: function(count) { + tasks = _.range(count); + }, + fn: function (async, done) { + async.every(tasks, function(i, cb) { + async.setImmediate(function() { + cb(i <= 600); + }); + }, done); + } + }, + { + name: "every - short circuit - false", + // args lists are passed to the setup function + args: [[500]], + setup: function(count) { + tasks = _.range(count); + }, + fn: function (async, done) { + async.every(tasks, function(i, cb) { + async.setImmediate(function() { + cb(i <= 60); + }); + }, done); + } + }, { name: "defer nextTick", fn: function (async, done) { -- cgit v1.2.1 From 529cd5ccb3b5ad4901d725602ab47bc96e847b12 Mon Sep 17 00:00:00 2001 From: Graeme Yeates Date: Thu, 2 Jul 2015 13:36:16 -0400 Subject: Test short circuiting of every* and some* --- test/test-async.js | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/test/test-async.js b/test/test-async.js index b7847bf..07b72e7 100755 --- a/test/test-async.js +++ b/test/test-async.js @@ -2272,6 +2272,33 @@ exports['everyLimit false'] = function(test){ }); }; +exports['everyLimit short-circuit'] = function(test){ + test.expect(2); + var calls = 0; + async.everyLimit([3,1,2], 1, function(x, callback){ + calls++; + callback(x === 1); + }, function(result){ + test.equals(result, false); + test.equals(calls, 1); + test.done(); + }); +}; + + +exports['someLimit short-circuit'] = function(test){ + test.expect(2); + var calls = 0; + async.someLimit([3,1,2], 1, function(x, callback){ + calls++; + callback(x === 1); + }, function(result){ + test.equals(result, true); + test.equals(calls, 2); + test.done(); + }); +}; + exports['any alias'] = function(test){ test.equals(async.any, async.some); test.done(); -- cgit v1.2.1