「我正在参与掘金会员专属活动-源码共读第一期,点击参与」
本篇文章介绍的是异步函数的并发控制。
有的时候,我们在进入页面的时候发起请求数量不只一个
- 如何控制并发数量呢?
- 还有怎么获取这些异步编程的状态?等待的和正在运行的各有几个?
- 如何将等待的请求能够手动取消掉?
这时候p-limit就登场了。
安装
npm install p-limit
使用
import pLimit from 'p-limit';
const limit = pLimit(1);
const input = [
limit(() => fetchSomething('foo')),
limit(() => fetchSomething('bar')),
limit(() => doSomething())
];
const result = await Promise.all(input);
console.log(result);
pLimit设置并发控制的数量,返回一个limit对象。limit可以获取等待的异步函数数量和已经执行的异步函数数量limit同时还可以传入异步函数及若干个参数放入异步队列(对应源码的queue)中。
源码
源码路径
根目录/index.js
解析源码
- 主函数在源码的第三行,传入的参数是
1以及以上的整数 - 通过
yocto-queue创建了一个队列queue - 声明了两个函数
next和run,next是做activeCount递减和出队的操作。run是用来执行异步函数和activeCount递增的。 enqueue作用是将传入的异步函数通过run进行包裹的并放入队列,然后会等待一个微任务执行完毕之后,在activeCount小于并发数量并且队列长度大于0的情况下出队操作。等待微任务执行完毕的目的是为了等待activeCount更新。generator函数返回一个Promise对象,里面包裹的是enqueue函数- 最后通过
defineProrperties给generator批量增加属性:activeCount,pendingCount,clearQueue
回顾一下:
const enqueue = (fn, resolve, args) => {
queue.enqueue(run.bind(undefined, fn, resolve, args));
(async () => {
// 下面这段代码其实还是很巧妙的,通过模拟一个微任务,能得到`activeCount`的最新值,因为`run`方法本身是一个异步函数。如果直接获取`activeCount`可能是还没执行异步函数之前的值。
await Promise.resolve();
if (activeCount < concurrency && queue.size > 0) {
queue.dequeue()();
}
})();
};
结束语
这段源码利用了yocto-queue的队列数据结构来作为异步函数的存储。如果有合适的库,引用进来,对于我们实现自己的逻辑还是很方便的。所以认识优秀的库更多,对我们的帮助更大。