ㅤㅤㅤ
ㅤㅤㅤ
ㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤ(要想成功,你必须自我制造机会,绝不能愚蠢地坐在路边,等待有人经过,邀请你同往财富与幸福之路。——歌夫)
ㅤㅤㅤ
ㅤㅤㅤ
ㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤ
前言
在使用nodejs开发后端业务过程中,我们难免要对异步IO流进行控制,以免内存,CPU,流量等突发导致数据库告警异常。
我们常用的异步流程控制库有bluebird,async等
但我们有时只需要使用’map’api来限制并发却引入一个庞大的npm包,这显然是得不偿失的,所以我们在这里手动实现一个promise.map
源码
/**
* promise.map 并行限流控制
* @param iterable 需要处理的数组
* @param mapper 执行的回调函数
* @param options 其他配置 concurrency 并发数,用于控制同时执行数
* @returns 返回值列表
*/
public static async promiseMap(iterable, mapper, options) {
options = options || {};
// 默认并发为1
let concurrency = options.concurrency || 1;
// 当前循环下标
let index = 0;
// 处理结果列表
const results = [];
// 数组迭代器 通过.next取值 如果.next.done为真 则取值完毕
const iterator = iterable[Symbol.iterator]();
// promise列表
const promises = [];
// 具体执行函数
const wrappedMapper = ()=> {
// 取下一个值
const next = iterator.next();
// 不存在则返回
if (next.done) return null;
// 每次记录下标,用于回调函数使用
const i = index++;
// 执行回调函数
const mapped = mapper(next.value, i);
// 执行promise
return Promise.resolve(mapped).then(resolved => {
// 处理结果赋值
results[i] = resolved;
// 继续递归调用
return wrappedMapper();
})
};
/**
* 通过循环并发数来限流并行任务
* 每一个并发都会生成一个promise执行链条,每一个promise链条会反复递归取值调用
* 比如并发是2 则生成两个promise链条放入promise.all中执行。每一个链条都会持续取值执行
*/
while (concurrency-- > 0) {
// 获取promise执行链
const promise = wrappedMapper();
// 存在则放入primise列表
if (promise) promises.push(promise);
else break;
}
// 并行执行promise链条
await Promise.all(promises);
// 返回结果
return results;
}
使用示例
await promiseMap([], (v) => // .... code, { concurrency: 1 });