SuperYan - Promise 2023-02-22T19:18:00+08:00 Typecho https://www.hblyan.com/feed/atom/tag/Promise/ <![CDATA[【性能优化】利用Promise控制请求并发数量(批量图片上传)]]> https://www.hblyan.com/archives/125.html 2023-02-22T19:18:00+08:00 2023-02-22T19:18:00+08:00 SuperYan http://www.hblyan.com

背景:因为JavaScript运行是单线程的,但是可以利用异步的promise去同时发出多个网络请求,但是一次过多的请求就会造成服务器压力或者其他复杂逻辑的负担等。

方案:利用promise限制同一时间调用的请求

应用:图片获取、文件上传等

刚开始 我的想法是利用 promise.all([...])的想法,虽然这个很容易就可以实现,但是有一个弊端就是等所有的all执行完才能执行下一次,那么能不能再次基础上,保证并发的过程中一直是达到我们的limit值呢而不会空闲?

看下面这个图,当我们有无数个请求时候,我只给当前线程开辟同时调用四个api的坑位,那么哪一个坑位结束就需要下一个顶上,同时保证中间的坑位一直是满的,那么就实现了并发限流的目的了。

image-20230222190627093

/**
* len 请求的总数量
* limit 坑位的数量
*/
function limitPromise(len = 10, limit) {
    let count = 0; //当前执行的promise数量,记录已占有的坑位
    let finishCount = 0; //已经完成的数量

    function run() {
        return new Promise((res, rej) => {
            count++ //有一个新的人 入坑了
            let time = Math.floor(Math.random() * 10 * 1000)
            console.log(time); //记录需要占坑的时间
            console.log(new Date()); //入坑的时间
            setTimeout(() => {
                res("成功")
            }, time)
        }).then(res => {
            count-- // 离开坑过后,空闲坑位
            finishCount++ //总数+1
            console.log(`已上传 ${finishCount}`);
            if (finishCount <= len && count <= 3) { //如果总数还有剩余,坑位还有剩余 那么执行一下操作
                run() //继续入坑
            } else {
                console.log("执行完毕");
            }
        })

    }

    for (let i = 0; i < limit; i++) { //初始化 开辟坑位
        run()
    }

}

limitPromise(10, 3)

image-20230222191357338

执行结果如上: 可以看到初始化3个坑位,然后每次有坑位执行完下一个请求就会进入,知道完成全部的操作。每次并发的最多只有3个~

以上大致 的意思 应该能看明白,实际场景只需要替换len 和每次执行的异步操作即可~

]]>