Repository: caolan/async (js)

Issue:
applyEach arguments position
Currently the `applyEach` and `applyEachSeries` functions have the following type signature:

``` js
async.applyEach(fns, ...args?, callback?)
```

Having a rest parameter in the middle of the arguments list is very difficult to write a type annotation for. It's currently not possible in either Flow or TypeScript, which is why you see stuff [like this](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/async/async.d.ts#L132-L133) (I'm writing a similar type definition for Flow right now).

Would it be okay to switch the argument order around and make callback nullable so it is like this?

``` js
async.applyEach(fns, callback | null, ...args?)
```

Or use an array instead of a rest parameter?

``` js
async.applyEach(fns, args?: Array<any>, callback?)
```


Pull request description:
BREAKING CHANGE: remove partial application feature of applyEach
Fixes #1228 , making it more type-able.

This reduces the utility of `applyEach`, though.

I'm almost in favor of removing the whole method.   I couldn't find any examples of it being used in the wild, and has always been a strange method.

Patch:
diff --git a/lib/eachSeries.js b/lib/eachSeries.js
index a23aef5..3831456 100644
--- a/lib/eachSeries.js
+++ b/lib/eachSeries.js
@@ -6,7 +6,7 @@ import awaitify from './internal/awaitify'
  *
  * Note, that unlike [`each`]{@link module:Collections.each}, this function applies iteratee to each item
  * in series and therefore the iteratee functions will complete in order.
- 
+
  * @name eachSeries
  * @static
  * @memberOf module:Collections
diff --git a/lib/internal/applyEach.js b/lib/internal/applyEach.js
index f95d8ac..c08a5eb 100644
--- a/lib/internal/applyEach.js
+++ b/lib/internal/applyEach.js
@@ -1,17 +1,14 @@
-import initialParams from './initialParams';
 import wrapAsync from './wrapAsync';
+import awaitify from './awaitify'
 
-export default function applyEach(eachfn) {
-    return function(fns, ...callArgs) {
-        var go = initialParams(function(args, callback) {
+export default function (eachfn) {
+    return function applyEach(fns, ...callArgs) {
+        const go = awaitify(function (callback) {
             var that = this;
             return eachfn(fns, (fn, cb) => {
-                wrapAsync(fn).apply(that, args.concat(cb));
+                wrapAsync(fn).apply(that, callArgs.concat(cb));
             }, callback);
         });
-        if (callArgs.length) {
-            return go.apply(this, callArgs);
-        }
         return go;
     };
 }


Test patch:
diff --git a/test/applyEach.js b/test/applyEach.js
index 4a67ee4..a5fce95 100644
--- a/test/applyEach.js
+++ b/test/applyEach.js
@@ -27,7 +27,7 @@ describe('applyEach', () => {
                 cb(null, 3);
             }, 18);
         };
-        async.applyEach([one, two, three], 5, (err, results) => {
+        async.applyEach([one, two, three], 5)((err, results) => {
             assert(err === null, err + " passed instead of 'null'");
             expect(call_order).to.eql(['two', 'one', 'three']);
             expect(results).to.eql([1, 2, 3]);
@@ -51,7 +51,7 @@ describe('applyEach', () => {
             throw new Error('third task - should not get here');
         }
 
-        async.applyEach({one, two, three}, 5, () => {
+        async.applyEach({one, two, three}, 5)(() => {
             throw new Error('final callback - should not get here');
         });
 
@@ -84,7 +84,7 @@ describe('applyEach', () => {
                 cb(null, 3);
             }, 15);
         }
-        async.applyEachSeries([one, two, three], 5, (err, results) => {
+        async.applyEachSeries([one, two, three], 5)((err, results) => {
             assert(err === null, err + " passed instead of 'null'");
             expect(call_order).to.eql(['one', 'two', 'three']);
             expect(results).to.eql([1, 2, 3]);
@@ -109,7 +109,7 @@ describe('applyEach', () => {
         function three(/*, cb */) {
             throw new Error('third task - should not get here');
         }
-        async.applyEachSeries([one, two, three], 5, () => {
+        async.applyEachSeries([one, two, three], 5)(() => {
             throw new Error('final callback - should not get here');
         });
 
@@ -118,35 +118,4 @@ describe('applyEach', () => {
             done();
         }, 25);
     });
-
-    it('applyEach partial application', (done) => {
-        var call_order = [];
-        var one = function (val, cb) {
-            expect(val).to.equal(5);
-            setTimeout(() => {
-                call_order.push('one');
-                cb(null, 1);
-            }, 10);
-        };
-        var two = function (val, cb) {
-            expect(val).to.equal(5);
-            setTimeout(() => {
-                call_order.push('two');
-                cb(null, 2);
-            }, 5);
-        };
-        var three = function (val, cb) {
-            expect(val).to.equal(5);
-            setTimeout(() => {
-                call_order.push('three');
-                cb(null, 3);
-            }, 15);
-        };
-        async.applyEach([one, two, three])(5, (err, results) => {
-            if (err) throw err;
-            expect(call_order).to.eql(['two', 'one', 'three']);
-            expect(results).to.eql([1, 2, 3]);
-            done();
-        });
-    });
 });
diff --git a/test/es2017/asyncFunctions.js b/test/es2017/asyncFunctions.js
index efb6555..553b7f4 100644
--- a/test/es2017/asyncFunctions.js
+++ b/test/es2017/asyncFunctions.js
@@ -272,14 +272,14 @@ module.exports = function () {
      */
 
     it('should handle async functions in applyEach', (done) => {
-        async.applyEach([asyncIdentity, asyncIdentity])(input, (err, result) => {
+        async.applyEach([asyncIdentity, asyncIdentity], input)((err, result) => {
             expect(result).to.eql([input, input]);
             done(err);
         });
     });
 
     it('should handle async functions in applyEachSeries', (done) => {
-        async.applyEachSeries([asyncIdentity, asyncIdentity])(input, (err, result) => {
+        async.applyEachSeries([asyncIdentity, asyncIdentity], input)((err, result) => {
             expect(result).to.eql([input, input]);
             done(err);
         });
diff --git a/test/es2017/awaitableFunctions.js b/test/es2017/awaitableFunctions.js
index b45b56c..55bcc9e 100644
--- a/test/es2017/awaitableFunctions.js
+++ b/test/es2017/awaitableFunctions.js
@@ -316,7 +316,22 @@ module.exports = function () {
      * Control flow
      */
 
-    // TODO:  figure out to do with applyEach
+    it('should return a Promise: applyEach', async () => {
+        const calls = []
+        await async.applyEach([
+            async (v, x) => { calls.push(v, x) },
+            async (v, x) => { calls.push(v, x) }
+        ], 5, 6)();
+        expect(calls).to.eql([5, 6, 5, 6])
+    })
+    it('should return a Promise: applyEachSeries', async () => {
+        const calls = []
+        await async.applyEachSeries([
+            async (v, x) => { calls.push(v, x) },
+            async (v, x) => { calls.push(v, x) }
+        ], 5, 6)();
+        expect(calls).to.eql([5, 6, 5, 6])
+    })
 
     it('should return a Promise: auto', async () => {
         expect (async.auto.name).to.contain('auto')
diff --git a/test/priorityQueue.js b/test/priorityQueue.js
index 1a8cc76..c3ece02 100644
--- a/test/priorityQueue.js
+++ b/test/priorityQueue.js
@@ -239,7 +239,7 @@ describe('priorityQueue', () => {
             q.push('foo4', 1, () => {calls.push('foo4 cb');});
         });
     });
-    
+
     it('should not call the drain callback if receives empty push and tasks are still pending', (done) => {
         var call_order = [];
 
@@ -247,21 +247,21 @@ describe('priorityQueue', () => {
             call_order.push('process ' + task);
             callback('error', 'arg');
         }, 1);
-        
+
         q.push(1, 1, (err, arg) => {
             expect(err).to.equal('error');
             expect(arg).to.equal('arg');
             call_order.push('callback ' + 1);
         });
-        
+
         q.push(2, 1, (err, arg) => {
             expect(err).to.equal('error');
             expect(arg).to.equal('arg');
             call_order.push('callback ' + 2);
         });
-        
+
         expect(q.length()).to.equal(2);
-        
+
         q.drain = function () {
             expect(call_order).to.eql([
                 'process 1', 'callback 1',
@@ -272,7 +272,7 @@ describe('priorityQueue', () => {
             expect(q.running()).to.equal(0);
             done();
         };
-        
+
         q.push([], 1, () => {});
     });
 });