异步控制流程 遍历篇detect、every

文章目录

  • 基础方法
    • arrayEachValue
    • baseEachValue
    • symbolEachValue
    • once
    • timesSync
  • 异步遍历
    • detect
    • detectLimit
    • detectSeries
    • every
    • everySeries
    • everyLimit

基础方法

arrayEachValue

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

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

baseEachValue

function baseEachValue(object, iterator, createCallback, keys) {
  var key, value;
  var index = -1;
  var size = keys.length;

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

symbolEachValue

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

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

once

function once(func) {
  return function(err, res) {
    var fn = func;
    func = noop;
    fn(err, res);
  };
}

timesSync

  • 遍历指定次数
function timesSync(n, iterator) {
  var index = -1;
  while (++index < n) {
    iterator(index);
  }
}

异步遍历

detect

  • 当返回结果为true时立即执行回调

基本使用:

var array = [1, 3, 2];
var iterator = function(num, done) {
  setTimeout(function() {
    order.push(num);
    done(null, num==1);
  }, num * 10);
};
nac.detect(array, iterator, function(err, res) {
  console.log(res); // 1
  console.log(order); // [1] ,在这一刻触发回调时,order数组的内容
  setTimeout(()=>{
    console.log(order) // [1,2,3]
  },4000)
});

实现:

const detect = createDetect(arrayEachValue, baseEachValue, symbolEachValue, true);

function createDetect(arrayEach, baseEach, symbolEach, bool) {
	return function(collection, iterator, callback) {
	  
	  callback = callback || noop;
      var size, keys;
      var completed = 0;
      // 区分不同类型的遍历
      if (isArray(collection)) {
        size = collection.length;
        arrayEach(collection, iterator, createCallback);  // createCallback会闭包保存当前遍历的值
      } else if (!collection) {
      } else if (iteratorSymbol && collection[iteratorSymbol]) { // var iteratorSymbol = typeof Symbol === func && Symbol.iterator;
        size = symbolEach(collection, iterator, createCallback);
        size && size === completed && callback(null);
      } else if (typeof collection === obj) {
        keys = nativeKeys(collection); // Object.keys
        size = keys.length;
        baseEach(collection, iterator, createCallback, keys);
      }
      if (!size) {
        callback(null);
      }

      function createCallback(value) {  // value为闭包保存的遍历元素
        var called = false;
        return function done(err, res) {
          if (called) {
            throwError();
          }
          called = true;
          if (err) {
            callback = once(callback);//只触发一次
            callback(err);
          } else if (!!res === bool) { //当返回值为true时
            callback = once(callback);
            callback(null, value);
          } else if (++completed === size) {
            callback(null);
          }
        };
      }
	}
}

detectLimit

  • 限制每次异步数量
var detectLimit = createDetectLimit(true);

function createDetectLimit(bool) {
  return function(collection, limit, iterator, callback) {
    callback = callback || noop;
    var size, index, key, value, keys, iter, item, 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;
      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);
    }
    
    timesSync(limit > size ? size : limit, iterate);

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

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

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

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

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

    function objectIteratorWithKey() {
      if (started < size) {
        key = keys[started++];
        value = collection[key];
        iterator(value, key, createCallback(value));
      }
    }

    function createCallback(value) {
      var called = false;
      return function(err, res) {
        if (called) {
          throwError();
        }
        called = true;
        if (err) {
          iterate = noop;
          callback = once(callback);
          callback(err);
        } else if (!!res === bool) { // 返回true立即执行回调
          iterate = noop;
          callback = once(callback);
          callback(null, value);
        } else if (++completed === size) {
          callback(null);
        } else if (sync) {
          nextTick(iterate);
        } else {
          sync = true;
          iterate();
        }
        sync = false;
      };
    }
  };
}

detectSeries

  • 串行执行,当上一个异步任务结束后,才会触发下一个异步任务
var detectSeries = createDetectSeries(true);

function createDetectSeries(bool) {
  return function(collection, iterator, callback) {
    callback = onlyOnce(callback || noop);
    var size, key, value, keys, iter, item, iterate;
    var sync = false;
    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;
      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);
    }
    iterate();

    function arrayIterator() {
      value = collection[completed];
      iterator(value, done);
    }

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

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

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

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

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

    function done(err, res) {
      if (err) {
        callback(err);
      } else if (!!res === bool) {
        iterate = throwError;
        callback(null, value);
      } else if (++completed === size) {
        iterate = throwError;
        callback(null);
      } else if (sync) {
        nextTick(iterate);
      } else {
        sync = true;
        iterate();
      }
      sync = false;
    }
  };
}

every

function createEvery(arrayEach, baseEach, symbolEach) {
  var deny = createDetect(arrayEach, baseEach, symbolEach, false); // 注意最后一个参数是false,表明detect中为false时触发callback

  return function every(collection, iterator, callback) {
    callback = callback || noop;
    deny(collection, iterator, done);

    function done(err, res) {
      if (err) {
        return callback(err);
      }
      callback(null, !res);
    }
  };
}

everySeries

function createEverySeries() {
  var denySeries = createDetectSeries(false); // 注意传递的是false

  return function everySeries(collection, iterator, callback) {
    callback = callback || noop;
    denySeries(collection, iterator, done);

    function done(err, res) {
      if (err) {
        return callback(err);
      }
      callback(null, !res);
    }
  };
}

everyLimit

function createEveryLimit() {
  var denyLimit = createDetectLimit(false); // 注意传递的是false

  return function everyLimit(collection, limit, iterator, callback) {
    callback = callback || noop;
    denyLimit(collection, limit, iterator, done);

    function done(err, res) {
      if (err) {
        return callback(err);
      }
      callback(null, !res);
    }
  };
}

你可能感兴趣的:(设计模式&代码优化,javascript,json,算法)