简单的前端任务队列

背景
在开发中,我们会遇到一些使用多个异步请求但返回数据需要按序的问题,如前端导出、多个文件上传,你可能会想到使用结合并发限制下分组处理使用Promise.all,虽然说这种方式可以提高请求的速度,但终归的得等到所有响应回来后才可进入下一个分组。这时候我们就可以用结合并发数,结合队列的特点让请求有序发出。
介绍
结合网上其他大佬的做法实现了一些改造,接下来让我们来介绍一下如何实现一个在限制最大同时并发数同时并在请求失败时可以重发的通用请求并发队列:

export default class RequestQueue {
    constructor(maxLimit = 5, retryLimit = 2) {
        //最大同时请求数
        this.maxLimit = maxLimit;
        //尝试总数
        this.retryLimit = retryLimit;

        //等待执行的任务队列
        this.taskQueue = [];
        //当前请求并发数
        this.currentRequestCount = 0;

		//当前请求成功数
        this.doneCount = 0;
    }


	/*
     *@functionName:  exec
     *@params1: request(异步请求 调用测传入 需为Promise实例)
     *@params2: callBack 回调函数 一般用于前端progress统计当前进度
    */
    async exec(request, callBack = () => {}) {
        let result = [];
        
        // 并发限制
        if (this.currentRequestCount >= this.maxLimit) {
            await this.pause(); // 暂停执行 入队
        }
        
        // 执行队列长度+1
        this.currentRequestCount++;

        // 设置队列当前任务的执行次数
        for (let retryCount = this.retryLimit; retryCount > 0; retryCount--) {
            let done = false;
            try {
            	//request传入的必须是一个promise实例
                result = await request();
                done = true;
                this.doneCount++;
                return Promise.resolve(result);
            } catch (error) {
                // 最后一次重试失败时停止重试,返回报错
                if (retryCount === 1) {
                    done = true;
                    return Promise.reject(error); // 错误只会抛出一次
                }
            } finally {
                if (done) {
                    callBack(this.doneCount);
                    this.currentRequestCount--;
                    this.next(); //任务队列首部出队
                }
            }
        }
    }

    next() {
        if (this.taskQueue.length <= 0) return;
        const resolve = this.taskQueue.shift();
        resolve(); // 取出任务队列首部执行
    }

    pause() {
        // 入队 将promise对象入队 不rosolve之前无法执行下个任务
        return new Promise((resolve) => this.taskQueue.push(resolve));
    }
}

使用方法:

const request = () => {
    return new Promise((resolve, reject) => {
     setTimeout(() => { resolve() }, 1000)
   })
};

let requestList = [];
const instance = new RequestQueue();
const callBack = () => {}


for (let i = 0; i < 100; i++ ) {
  requestList.push(instance.exec(request,callBack)
    .catch(err => {
        // 这里是否catch(err)取决于是否允许某个任务失败时,其他任务继续执行
       console.log(err)
    })
  )
}

Promise.all(requestList).then((res) => {
	//如需获取数据
	console.log(res.falt(1))
})
  .catch(err => console.log(err)) 

结语
感谢你的观看,这种写法可能还存在问题,仅供学习。

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值