p-limit,优雅地实现并发

什么是并发?

并发,顾名思义,就是一起发生。而在前端中,并发大多是与请求挂钩的。

并发的场景

在前端开发中,难免要遇到并发请求的场景,比如说对大文件进行分片上传,文件有100M,而每个分片只有1M,因此要发送100次请求。

大家都知道浏览器是有并发限制的,一次性只允许发送6个请求,如果一次性发送100个请求,肯定会造成卡顿,此外,如果这时候除了文件上传的请求,还有其他请求,也会造成不好的体验,因此我们有必要手动对请求进行并发限制。

在github上有很多实现并发请求的库。p-limit就是一个非常优秀的实现并发请求的库,接下来,让我们来深入了解一下这个库的源码,学习一下如何优雅地实现并发。

源码

p-limit主要是通过队列的形式将所有任务推入到队列中,只有当前执行数量少于并发数且队列不为空时才会从队列中取出任务执行。

生成Promise实例

javascript 复制代码
export default function pLimit(concurrency) {
    const queue = new Queue();
    let activeCount = 0;
    const generator = (fn, ...args) => new Promise(resolve => {
        enqueue(fn, resolve, args);
    });
        .....
 }

首先p-limit的队列用的是yocto-queue这个库,主要用到了入队和出队的方法。 concurrency 就是并发数,activeCount 则是当前执行的任务数。 函数generator用于生成一个新的Promise实例,将请求任务Promise的状态改变函数resolve 以及剩余参数传入到enqueue函数中。

enqueue入队

scss 复制代码
const enqueue = (fn, resolve, args) => {
    queue.enqueue(run.bind(undefined, fn, resolve, args));
    (async () => {
        await Promise.resolve();
        if (activeCount < concurrency && queue.size > 0) {
            queue.dequeue()();
        }
    })();
};

enqueue函数中,调用yocto-queue的enqueue方法,将经过run调用bind方法创建新函数推入到队列中。

下面的async/await立即执行函数 则是为了确保比较是在队列中的请求任务执行之后进行获取到最新的任务执行数,如果少于并发数的话且队列不为空,则从队列中取出任务执行。

run执行

ini 复制代码
const run = async (fn, resolve, args) => {
    activeCount++;
    const result = (async () => fn(...args))();
    resolve(result);
    try {
        await result;
    } catch {}
    next();
};

run函数就是用来执行请求任务的,activeCount++,当前执行的任务数加一。获取到请求的结果,通过generator函数传递过来的resolve改变它生成的Promise的状态。

这里async/await的作用是等待当前任务执行完再执行下个任务,next函数也就是用于执行下一个任务的。

next执行下一个任务

ini 复制代码
const next = () => {
    activeCount--;
    if (queue.size > 0) {
        queue.dequeue()();
    }
};

当执行next的时候,说明上一个任务已经执行完毕了,因此将activeCount减一,同时如果队列不为空,取出一个任务来执行。

其他属性

至此p-limit的核心代码已经讲解完毕,除此之外,p-limit还额外提供了三个属性,分别是activeCountpendingCountclearQueue

css 复制代码
Object.defineProperties(generator, {
    activeCount: {
            get: () => activeCount,
    },
    pendingCount: {
            get: () => queue.size,
    },
    clearQueue: {
            value: () => {
                    queue.clear();
            },
    },
});

其中activeCount表示当前执行的任务数 、pendingCount表示等待执行的任务数 ,他们都是只读 的,不允许被修改,而clearQueue这个属性则可以用来清除队列中未执行的请求,这三个属性拓展了p-limit的功能,让它变得更为强大。

除此之外,为了提升一定的容错,p-limit还对传入的并发数进行的判断,需要满足如下条件:是数字、不能为Infinity、且必须大于0,如果不满足的话,则会抛出错误。

javascript 复制代码
if (!((Number.isInteger(concurrency) || concurrency === Number.POSITIVE_INFINITY) && concurrency > 0)) {
    throw new TypeError('Expected `concurrency` to be a number from 1 and up');
}

总结

以上就是关于p-limit解读的全部内容啦,这仅是我在学习p-limit源码时的理解,如果哪里有误欢迎大佬指出,以后我也会分享更多关于源码的解读!

相关推荐
我要洋人死几秒前
导航栏及下拉菜单的实现
前端·css·css3
科技探秘人12 分钟前
Chrome与火狐哪个浏览器的隐私追踪功能更好
前端·chrome
科技探秘人12 分钟前
Chrome与傲游浏览器性能与功能的深度对比
前端·chrome
JerryXZR18 分钟前
前端开发中ES6的技术细节二
前端·javascript·es6
七星静香20 分钟前
laravel chunkById 分块查询 使用时的问题
java·前端·laravel
q24985969322 分钟前
前端预览word、excel、ppt
前端·word·excel
小华同学ai28 分钟前
wflow-web:开源啦 ,高仿钉钉、飞书、企业微信的审批流程设计器,轻松打造属于你的工作流设计器
前端·钉钉·飞书
Gavin_91537 分钟前
【JavaScript】模块化开发
前端·javascript·vue.js
懒大王爱吃狼2 小时前
Python教程:python枚举类定义和使用
开发语言·前端·javascript·python·python基础·python编程·python书籍
逐·風6 小时前
unity关于自定义渲染、内存管理、性能调优、复杂物理模拟、并行计算以及插件开发
前端·unity·c#