异步控制流程 遍历篇reduce

基础方法

异步遍历

reduce

基本使用

  • 通过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
});

实现

  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 && 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) { // 通过 done 传递result
      if (err) {
        callback(err, result);
      } else if (++completed === size) {
        iterator = throwError;
        callback(null, result);
      } else if (sync) { // 避免大量的同步任务阻塞时间循环,所以变成异步任务
        nextTick(function() {
          iterate(result);
        });
      } else {
        sync = true;
        iterate(result);
      }
      sync = false;
    }
  }

reduceRight

  • reduceRight,从集合最后一位开始遍历
  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; //从数组最后一位开始
      iterate = iterator.length === 4 ? arrayIteratorWithIndex : arrayIterator;
    } else if (!collection) {
    } else if (iteratorSymbol && collection[iteratorSymbol]) {
      // 对于symbol类型,先求出所有的值,再根据索引逆序
      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

  • 和普通reduce的区别是:传入迭代器的是方法,需要执行并传递result

基本使用

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
});

实现:

function compose() {
  // 参数进行了翻转
  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) { // 这里的 callback 为 reduce 里的 done,会调用下一个任务或者最终回调
      // 第一次:newargs:[4]、fn:add1
      // 第二次:newargs:[5]、fn:mul3
      var func = function(err) { //任务中调用的callback
        // 第一次:nextargs:4+1=5
        // 第二次:nextargs:5*3=15
        var nextargs = slice(arguments, 1);// 将要传递给下一个任务的参数合并成一个,这也是不直接将callback传递的原因
        callback(err, nextargs);
      };
      // 第一次:newargs:[4,func]
      // 第二次:newargs:[5,func]
      newargs.push(func); //push的作用是把callback传入
      // 第一次:add1(4,func)
      // 第二次:mul3(5,func)
      fn.apply(self, newargs);
    }

    function done(err, res) {
      // [15]
      res = isArray(res) ? res : [res];
      res.unshift(err);
      callback.apply(self, res);
    }
  };
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值