异步控制流程 遍历篇map

基础方法

arrayEachIndex

function arrayEachIndex(array, iterator, createCallback) {
  var index = -1;
  var size = array.length;

  if (iterator.length === 3) {
    while (++index < size) {
      iterator(array[index], index, createCallback(index));
    }
  } else {
    while (++index < size) {
      iterator(array[index], createCallback(index));
    }
  }
}

baseEachKey

  • 兼容对象和数组两种便利方式
function baseEachKey(object, iterator, createCallback, keys) {
  var key;
  var index = -1;
  var size = keys.length;

  if (iterator.length === 3) {
    while (++index < size) {
      key = keys[index];
      iterator(object[key], key, createCallback(key));
    }
  } else {
    while (++index < size) {
      key = keys[index];
      iterator(object[key], createCallback(key));
    }
  }
}

symbolEachIndex

function symbolEachIndex(collection, iterator, createCallback) {
  var item;
  var index = 0;
  var iter = collection[iteratorSymbol]();

  if (iterator.length === 3) {
    while ((item = iter.next()).done === false) {
      iterator(item.value, index, createCallback(index++));
    }
  } else {
    while ((item = iter.next()).done === false) {
      iterator(item.value, createCallback(index++));
    }
  }
  return index;
}

timeSync 一次执行多少个迭代器

  • 限制执行次数
function timesSync(n, iterator) {
  var index = -1;
  while (++index < n) {
    iterator(index);
  }
}

异步遍历

map

  • 不保证异步执行顺序,但会保证异步结果顺序
  • 通过闭包保存当前遍历的索引,done时记录结果
var array = [1, 3, 2];
var iterator = function(num, done) {
  setTimeout(function() {
    done(null, num);
  }, num * 10);
};
nac.map(array, iterator, function(err, res) {
  console.log(res); // [1, 3, 2];
});

实现

const map = createMap(arrayEachIndex, baseEachIndex, symbolEachIndex, true);

function createMap(arrayEach, baseEach, symbolEach, useArray) {
  var init, clone;
  if (useArray) {
    init = Array;
    clone = createArray; // 数组浅拷贝
  } else {
    init = function() {
      return {};
    };
    clone = objectClone; // 对象浅拷贝
  }

  return function(collection, iterator, callback) {
    callback = callback || noop;
    var size, keys, result;
    var completed = 0;

    if (isArray(collection)) {
      size = collection.length;
      result = init(size);// 创建数组
      arrayEach(collection, iterator, createCallback);
    } else if (!collection) {
    } else if (iteratorSymbol && collection[iteratorSymbol]) {
      // TODO: size could be changed
      result = init(0);
      size = symbolEach(collection, iterator, createCallback);
      size && size === completed && callback(null, result);
    } else if (typeof collection === obj) {
      keys = nativeKeys(collection);// Object.keys()
      size = keys.length;
      result = init(size);
      baseEach(collection, iterator, createCallback, keys);
    }
    if (!size) {
      callback(null, init());
    }
    
    function createCallback(key) { //key是通过闭包保存的索引
      return function done(err, res) {
        if (key === null) {
          throwError();
        }
        if (err) {
          key = null;
          callback = once(callback);
          callback(err, clone(result));
          return;
        }
        // 存储map每一次遍历结果
        result[key] = res;
        key = null;
        if (++completed === size) {
          callback(null, result);
        }
      };
    }
  };
}

mapSeries

  • 保证异步串行调用顺序和返回数组结果顺序
  • 在done的回调中执行下一个遍历任务
  function mapSeries(collection, iterator, callback) {
    callback = callback || noop;
    var size, key, keys, iter, item, result, iterate;
    var sync = false;
    var completed = 0;

    if (isArray(collection)) {
      size = collection.length;
      iterate = iterator.length === 3 ? arrayIteratorWithIndex : arrayIterator;
    } else if (!collection) {
      // iteratorSymbol = typeof Symbol === func && Symbol.iterator;
    } else if (iteratorSymbol && collection[iteratorSymbol]) { // 迭代器遍历
      size = Infinity;
      result = [];
      iter = collection[iteratorSymbol]();
      iterate = iterator.length === 3 ? symbolIteratorWithKey : symbolIterator;
    } else if (typeof collection === obj) {
      keys = nativeKeys(collection);
      size = keys.length;
      iterate = iterator.length === 3 ? objectIteratorWithKey : objectIterator;
    }
    if (!size) {
      return callback(null, []);
    }
    result = result || Array(size);
    iterate();

    function arrayIterator() {
      // 当completed==size后,iterator会被赋值成throwError,后续调用done进行报错
      iterator(collection[completed], done);
    }

    function arrayIteratorWithIndex() {
      iterator(collection[completed], completed, done);
    }

    function symbolIterator() {
      item = iter.next();
      // 当completed==size后,callback会被赋值成throwError,后续调用done进行报错
      item.done ? callback(null, result) : iterator(item.value, done);
    }

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

    function objectIterator() {
      iterator(collection[keys[completed]], done);
    }

    function objectIteratorWithKey() {
      key = keys[completed];
      iterator(collection[key], key, done);
    }

    function done(err, res) {
      if (err) {
        iterate = throwError;
        callback = onlyOnce(callback);
        callback(err, createArray(result));
        return;
      }
      result[completed] = res;
      if (++completed === size) {
        iterate = throwError; // 避免后续调用
        callback(null, result);
        callback = throwError;// 避免后续调用
      } else if (sync) {
        nextTick(iterate);
      } else {
        sync = true;
        iterate();
      }
      sync = false;
    }
  }

mapLimit

  • 限制每一次异步请求的次数
  • 原理:只需要限制第一次发起请求的次数,然后在每一次请求回调中调用后续请求,即可实现每一次请求数量小于n

基本使用

var order = [];
var array = [1, 5, 3, 4, 2];
var iterator = function(num, done) {
  setTimeout(function() {
    order.push(num);
    done(null, num);
  }, num * 10);
};
async.mapLimit(array, 2, iterator, function(err, res) {
  console.log(res); // [1, 5, 3, 4, 2]
  console.log(order); // [1, 3, 5, 2, 4]
});

实现

 function mapLimit(collection, limit, iterator, callback) {
    callback = callback || noop;
    var size, index, key, keys, iter, item, result, iterate;
    var sync = false;
    var started = 0;
    var completed = 0;

    if (isArray(collection)) {
      size = collection.length;
      iterate = iterator.length === 3 ? arrayIteratorWithIndex : arrayIterator;
    } else if (!collection) {
    } else if (iteratorSymbol && collection[iteratorSymbol]) {
      size = Infinity;
      result = [];
      iter = collection[iteratorSymbol]();
      iterate = iterator.length === 3 ? symbolIteratorWithKey : symbolIterator;
    } else if (typeof collection === obj) {
      keys = nativeKeys(collection);
      size = keys.length;
      iterate = iterator.length === 3 ? objectIteratorWithKey : objectIterator;
    }
    if (!size || isNaN(limit) || limit < 1) {
      return callback(null, []);
    }
    result = result || Array(size);
    // 限制单次迭代器执行个数
    timesSync(limit > size ? size : limit, iterate);

    function arrayIterator() {
      index = started++;
      if (index < size) {
        iterator(collection[index], createCallback(index));
      }
    }

    function arrayIteratorWithIndex() {
      index = started++;
      if (index < size) {
        iterator(collection[index], index, createCallback(index));
      }
    }

    function symbolIterator() {
      item = iter.next();
      if (item.done === false) {
        iterator(item.value, createCallback(started++));
      } else if (completed === started && iterator !== noop) {
        iterator = noop;
        callback(null, result);
      }
    }

    function symbolIteratorWithKey() {
      item = iter.next();
      if (item.done === false) {
        iterator(item.value, started, createCallback(started++));
      } else if (completed === started && iterator !== noop) {
        iterator = noop;
        callback(null, result);
      }
    }

    function objectIterator() {
      index = started++;
      if (index < size) {
        iterator(collection[keys[index]], createCallback(index));
      }
    }

    function objectIteratorWithKey() {
      index = started++;
      if (index < size) {
        key = keys[index];
        iterator(collection[key], key, createCallback(index));
      }
    }
    // 闭包保存当前索引
    function createCallback(index) {
      return function(err, res) {
        if (index === null) {
          throwError();
        }
        if (err) {
          index = null;
          iterate = noop;
          callback = once(callback);
          callback(err, createArray(result));
          return;
        }
        result[index] = res;
        index = null;
        if (++completed === size) {
          iterate = throwError;
          callback(null, result);
          callback = throwError;
        } else if (sync) {
          nextTick(iterate);
        } else {
          sync = true;
          iterate();
        }
        sync = false;
      };
    }
  }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值