Asynchronous control flow traversal reduce

Article directory

  • basic method
  • asynchronous traversal
    • reduce
    • reduceRight
    • compose

Basic method

Asynchronous traversal

reduce

basic use

  • The next iterator will be executed when the parameter is passed to the next one through done
var collection = [1, 3, 2, 4];
var iterator = function(result, num, done) {<!-- -->
  setTimeout(function() {<!-- -->
    done(null, result + num);
  }, num * 10);
};
async.reduce(collection, 5, iterator, function(err, res) {<!-- -->
  console. log(res); // 15
});

accomplish

 function reduce(collection, result, iterator, callback) {<!-- -->
    callback = onlyOnce(callback || noop);
    var size, key, keys, iter, item, iterate;
    var sync = false;
    var completed = 0;

    if (isArray(collection)) {<!-- -->
      size = collection. length;
      iterate = iterator. length === 4 ? arrayIteratorWithIndex : arrayIterator;
    } else if (!collection) {<!-- -->
    } else if (iteratorSymbol & amp; & amp; collection[iteratorSymbol]) {<!-- -->
      size = Infinity;
      iter = collection[iteratorSymbol]();
      iterate = iterator. length === 4 ? symbolIteratorWithKey : symbolIterator;
    } else if (typeof collection === obj) {<!-- -->
      keys = nativeKeys(collection);
      size = keys. length;
      iterate = iterator. length === 4 ? objectIteratorWithKey : objectIterator;
    }
    if (!size) {<!-- -->
      return callback(null, result);
    }
    iterate(result);

    function arrayIterator(result) {<!-- -->
      iterator(result, collection[completed], done);
    }

    function arrayIteratorWithIndex(result) {<!-- -->
      // results value key next
      iterator(result, collection[completed], completed, done);
    }

    function symbolIterator(result) {<!-- -->
      item = iter. next();
      item.done ? callback(null, result) : iterator(result, item.value, done);
    }

    function symbolIteratorWithKey(result) {<!-- -->
      item = iter. next();
      item.done ? callback(null, result) : iterator(result, item.value, completed, done);
    }

    function objectIterator(result) {<!-- -->
      iterator(result, collection[keys[completed]], done);
    }

    function objectIteratorWithKey(result) {<!-- -->
      key = keys[completed];
      iterator(result, collection[key], key, done);
    }

    function done(err, result) {<!-- --> // pass result through done
      if (err) {<!-- -->
        callback(err, result);
      } else if ( + + completed === size) {<!-- -->
        iterator = throwError;
        callback(null, result);
      } else if (sync) {<!-- --> // Avoid a large number of synchronous tasks blocking the time loop, so it becomes an asynchronous task
        nextTick(function() {<!-- -->
          iterate(result);
        });
      } else {<!-- -->
        sync = true;
        iterate(result);
      }
      sync = false;
    }
  }

reduceRight

  • reduceRight, traverse from the last digit of the collection
 function reduceRight(collection, result, iterator, callback) {<!-- -->
    callback = onlyOnce(callback || noop);
    var resIndex, index, key, keys, iter, item, col, iterate;
    var sync = false;

    if (isArray(collection)) {<!-- -->
      resIndex = collection.length; //Start from the last digit of the array
      iterate = iterator. length === 4 ? arrayIteratorWithIndex : arrayIterator;
    } else if (!collection) {<!-- -->
    } else if (iteratorSymbol & amp; & amp; collection[iteratorSymbol]) {<!-- -->
      // For the symbol type, first find all the values, and then reverse the order according to the index
      col = [];
      iter = collection[iteratorSymbol]();
      index = -1;
      while ((item = iter.next()).done === false) {<!-- -->
        col[ + + index] = item. value;
      }
      collection = col;
      resIndex = col. length;
      iterate = iterator. length === 4 ? arrayIteratorWithIndex : arrayIterator;
    } else if (typeof collection === obj) {<!-- -->
      keys = nativeKeys(collection);
      resIndex = keys. length;
      iterate = iterator. length === 4 ? objectIteratorWithKey : objectIterator;
    }
    if (!resIndex) {<!-- -->
      return callback(null, result);
    }
    iterate(result);

    function arrayIterator(result) {<!-- -->
      iterator(result, collection[--resIndex], done);
    }

    function arrayIteratorWithIndex(result) {<!-- -->
      iterator(result, collection[--resIndex], resIndex, done);
    }

    function objectIterator(result) {<!-- -->
      iterator(result, collection[keys[--resIndex]], done);
    }

    function objectIteratorWithKey(result) {<!-- -->
      key = keys[--resIndex];
      iterator(result, collection[key], key, done);
    }

    function done(err, result) {<!-- -->
      if (err) {<!-- -->
        callback(err, result);
      } else if (resIndex === 0) {<!-- -->
        iterate = throwError;
        callback(null, result);
      } else if (sync) {<!-- -->
        nextTick(function() {<!-- -->
          iterate(result);
        });
      } else {<!-- -->
        sync = true;
        iterate(result);
      }
      sync = false;
    }
  }

compose

  • The difference from ordinary reduce is: the method passed into the iterator needs to be executed and the result passed

basic use

function add1(n, callback) {<!-- -->
    setTimeout(function () {<!-- -->
        callback(null, n + 1);
    }, 10);
}

function mul3(n, callback) {<!-- -->
    setTimeout(function () {<!-- -->
        callback(null, n * 3);
    }, 10);
}

var add1mul3 = nac.compose(mul3, add1); //mul3(add1(4))
add1mul3(4, function (err, result) {<!-- -->
    // result now equals 15
    console.log(result) // 15
});

accomplish:

function compose() {<!-- -->
  // parameter flipped
  return seq.apply(null, reverse(arguments));
}

/**
 * @memberof async
 * @namespace seq
 */
function seq(/* functions... */) {<!-- -->
  //fns:[add1,mul3]
  var fns = createArray(arguments);

  return function() {<!-- -->
    var self = this
    // args: [4, callback]
    var args = createArray(arguments);
    var callback = args[args. length - 1];
    if (typeof callback === func) {<!-- -->
      args. pop();
    } else {<!-- -->
      callback = noop;
    }
    reduce(fns, args, iterator, done);

    function iterator(newargs, fn, callback) {<!-- --> // The callback here is done in reduce, which will call the next task or the final callback
      // First time: newargs:[4], fn:add1
      // Second time: newargs:[5], fn:mul3
      var func = function(err) {<!-- --> //callback called in the task
        // first time: nextargs:4 + 1=5
        // Second time: nextargs:5*3=15
        var nextargs = slice(arguments, 1);// Merge the parameters to be passed to the next task into one, which is why the callback is not passed directly
        callback(err, nextargs);
      };
      // first time: newargs:[4,func]
      // Second time: newargs:[5,func]
      newargs.push(func); //The function of push is to pass in the callback
      // first time: add1(4,func)
      // second time: mul3(5,func)
      fn.apply(self, newargs);
    }

    function done(err, res) {<!-- -->
      // [15]
      res = isArray(res) ? res : [res];
      res. unshift(err);
      callback.apply(self, res);
    }
  };
}