简体   繁体   中英

Waterfall style functions get wrong arguments passed

I'm trying to reverse engineer async's waterfall function to better understand how it works.
While I've come up with the following code which works mostly, it has one strange behavior I cannot explain: Arguments passed to the next function seem to get lost somewhere, being replaced by the load event in browsers and the require function in node.

My code:

const waterfall = (callbacks, callback) => {
  callback = callback || function() {
    };

  let counter      = 0,
      errors       = [],
      results      = [],
      nextExecutor = (err, res) => {
        let argsArray           = Array.from(arguments),
            error               = (argsArray.length >= 2 && !!argsArray[ 0 ]
                ? argsArray[ 0 ]
                : false
            ),
            result              = (error
                ? argsArray[ 1 ]
                : argsArray[ 0 ]
            ),
            currentIteration    = counter++,
            currentNextExecutor = (counter === callbacks.length
                ? () => {
              }
                : nextExecutor
            );

        if (error !== false) {
          errors.push(error);
        }

        results.push(result);

        callbacks[ currentIteration ].call(
          {},
          currentNextExecutor,
          result
        );

        if (counter === callbacks.length) {
          callback.call(
            {},
            (errors.length > 0
                ? errors[ 0 ]
                : null
            ),
            results
          );
        }
      };

  callbacks[ counter++ ](nextExecutor);
};

waterfall([
  function(next) {
    console.log('hi! this is first.');
    setTimeout(() => {
      next(null, 10);
    }, 200);
  },
  function(next, x) {
    console.log('hi! this is second: ' + x);
    setTimeout(() => {
      next(null, x);
    }, 200);
  },
  function(next, x) {
    console.log('hi! this is third: ' + x);
    x++;
    setTimeout(() => {
      next(null, x);
    }, 200);
  },
  function(next, x) {
    console.log('hi! this is last.');
    setTimeout(() => {
      next(null, x);
    }, 200);
  }
], (error, results) => {
  console.log('Error: ' + JSON.stringify(error));
  console.log('Results: ' + JSON.stringify(results));
});

Expected output:

hi! this is first.
hi! this is second: 10
hi! this is third: 10
hi! this is last.
Error: null
Results: [ 10, 10, 11, 11]

Actual output:

hi! this is first.
hi! this is second: function require(path) { ... }
hi! this is third: function require(path) { ... }
hi! this is last.
Error: {}
Results: [null,null,null]

I don't understand where things go wrong - the arguments object has no reference of the passed value.

Notice: This is not intended to mimic async source code, because I haven't looked at it yet. I wanted to solve the problem by myself for learning purposes.

Edit:

Since arrow functions don't bind their own arguments variable, I was using the parent scope arguments . Which, incidentially, was the load event in browsers or require in node.

Original Answer:

Solved the problem - interestingly enough, using arrow functions does not work as intended, though I don't know why. Swapping the declaration for nextExecutor to a standard function (and refactoring the argument handling a bit) seems to fix the issue.

Thus, the nextExecutor code looks like this:

nextExecutor = function(error, result) {
    let currentIteration    = counter++,
        currentNextExecutor = (counter === callbacks.length
            ? function() {}
            : nextExecutor
        );

    if (!!error) {
      errors.push(error);
    }

    results.push(result);

    callbacks[ currentIteration ].call(
      {},
      currentNextExecutor,
      result
    );

    if (counter === callbacks.length) {
      callback.call(
        {},
        (errors.length > 0
            ? errors[ 0 ]
            : null
        ),
        results
      );
    }
  };

  callbacks[ counter++ ](nextExecutor);
};

Well your problem was here

result = (error
  ? argsArray[ 1 ]
  : argsArray[ 0 ]
),

Since error is always false, result would be args[0] which is always null ?

argsArray[indexes] are inverted in other words ...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM