异步流程控制 遍历篇filter
文章目录
- 基础方法
- arrayEachIndexValue
- baseEachIndexValue
- symbolEachIndexValue
- compact
- timesSync
- 异步遍历
- filter
- filterLimit
- filterSeries
基础方法
arrayEachIndexValue
function arrayEachIndexValue(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(index, value));
}
} else {
while (++index < size) {
value = array[index];
iterator(value, createCallback(index, value));
}
}
}
baseEachIndexValue
function baseEachIndexValue(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(index, value));
}
} else {
while (++index < size) {
value = object[keys[index]];
iterator(value, createCallback(index, value));
}
}
}
symbolEachIndexValue
function symbolEachIndexValue(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(index++, value));
}
} else {
while ((item = iter.next()).done === false) {
value = item.value;
iterator(value, createCallback(index++, value));
}
}
return index;
}
compact
- 筛选数组中所有true的元素
function compact(array) {
var index = -1;
var size = array.length;
var result = [];
while (++index < size) {
var value = array[index];
if (value) {
result[result.length] = value;
}
}
return result;
}
timesSync
function timesSync(n, iterator) {
var index = -1;
while (++index < n) {
iterator(index);
}
}
异步遍历
filter
基本使用
// array
var order = [];
var array = [1, 3, 2];
var iterator = function(num, done) {
setTimeout(function() {
order.push(num);
done(null, num % 2);
}, num * 10);
};
async.filter(array, iterator, function(err, res) {
console.log(res); // [1, 3];
console.log(order); // [1, 2, 3]
});
实现
var filter = createFilter(arrayEachIndexValue, baseEachIndexValue, symbolEachIndexValue, true);
function createFilter(arrayEach, baseEach, symbolEach, bool) {
return function(collection, iterator, callback) {
callback = callback || noop;
var size, keys, result;
var completed = 0;
if (isArray(collection)) {
size = collection.length;
result = Array(size);
arrayEach(collection, iterator, createCallback);
} else if (!collection) {
} else if (iteratorSymbol && collection[iteratorSymbol]) {
result = [];
size = symbolEach(collection, iterator, createCallback);
size && size === completed && callback(null, compact(result));
} else if (typeof collection === obj) {
keys = nativeKeys(collection);
size = keys.length;
result = Array(size);
baseEach(collection, iterator, createCallback, keys);
}
if (!size) {
return callback(null, []);
}
function createCallback(index, value) { // 闭包记录索引和元素值
return function done(err, res) {
if (index === null) {
throwError();
}
if (err) {
index = null;
callback = once(callback);
callback(err);
return;
}
if (!!res === bool) { // 异步回调结果为true时才记录
result[index] = value; // 通过闭包index保存异步任务对应位置
}
index = null;
if (++completed === size) { // 会等到所有任务执行完毕后,筛选出true的元素
callback(null, compact(result));
}
};
}
};
}
filterLimit
- 限制每次执行的异步任务数量
var filterLimit = createFilterLimit(true);
function createFilterLimit(bool) {
return function(collection, limit, iterator, callback) {
callback = callback || noop;
var size, index, key, value, keys, iter, item, iterate, result;
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; // 注意迭代器类型不知道size有多少个
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) {
value = collection[index];
iterator(value, createCallback(value, index));
}
}
function arrayIteratorWithIndex() {
index = started++;
if (index < size) {
value = collection[index];
iterator(value, index, createCallback(value, index));
}
}
function symbolIterator() {
item = iter.next();
if (item.done === false) {
value = item.value;
iterator(value, createCallback(value, started++));
} else if (completed === started && iterator !== noop) { // completed === started 表明已迭代完毕,createCallback对于迭代器类型只负责++completed
iterator = noop;
callback(null, compact(result));
}
}
function symbolIteratorWithKey() {
item = iter.next();
if (item.done === false) {
value = item.value;
iterator(value, started, createCallback(value, started++));
} else if (completed === started && iterator !== noop) {
iterator = noop;
callback(null, compact(result));
}
}
function objectIterator() {
index = started++;
if (index < size) {
value = collection[keys[index]];
iterator(value, createCallback(value, index));
}
}
function objectIteratorWithKey() {
index = started++;
if (index < size) {
key = keys[index];
value = collection[key];
iterator(value, key, createCallback(value, index));
}
}
function createCallback(value, index) {
return function(err, res) {
if (index === null) {
throwError();
}
if (err) {
index = null;
iterate = noop;
callback = once(callback);
callback(err);
return;
}
if (!!res === bool) {
result[index] = value;
}
index = null;
if (++completed === size) {
callback = onlyOnce(callback);
callback(null, compact(result));
} else if (sync) {
nextTick(iterate);
} else {
sync = true;
iterate();
}
sync = false;
};
}
};
}
filterSeries
- 串行执行,在上一个任务done之后再执行下一个任务
var filterSeries = createFilterSeries(true);
function createFilterSeries(bool) {
return function(collection, iterator, callback) {
callback = onlyOnce(callback || noop);
var size, key, value, keys, iter, item, iterate;
var sync = false;
var completed = 0;
var result = [];
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, result) : iterator(value, done);
}
function symbolIteratorWithKey() {
item = iter.next();
value = item.value;
item.done ? callback(null, result) : iterator(value, completed, done);
}
function objectIterator() {
key = keys[completed];
value = collection[key];
iterator(value, done);
}
function objectIteratorWithKey() {
key = keys[completed];
value = collection[key];
iterator(value, key, done);
}
function done(err, res) {
if (err) {
callback(err);
return;
}
if (!!res === bool) {
result[result.length] = value;
}
if (++completed === size) {
iterate = throwError;
callback(null, result);
} else if (sync) {
nextTick(iterate);
} else {
sync = true;
iterate();
}
sync = false;
}
};
}