前端如何优雅处理请求高并发?

实现一个批量请求函数 multiRequest(urls, maxNum),要求如下: 

  • 要求最大并发数 maxNum 
  • 每当有一个请求返回,就留下一个空位,可以增加新的请求 
  • 所有请求完成后,结果按照 urls 里面的顺序依次打出
// 线程池思想, 最大线程数maxNum个

function request(url, callback) {
    console.log(url, "开始请求啦")
    return new Promise((resolve, reject)=>{
        setTimeout(()=>{
            resolve(url+"成功啦");
        }, Math.random() * 2000);
    })
}

function multi(maxNum = 5) {
    let pool = [];
    let wait = [];
    let ret = [];
    let count = 0;
    let emptyCallback = null;

    function task(url, s, f) {
        this.key = count;
        this.url = url;
        count++;
        this.ret = undefined;
        this.status = "pending";
        this.error = undefined;
        this.run = () => {
            this.status = "running";
            new Promise((resolve, reject) => {
                request(url)
                    .then(res => {
                        this.status = "success";
                        this.ret = res;
                        s();
                    }).catch(err => {
                        this.status = "error";
                        this.error = err;
                        f();
                    })
            })
        }
    }

    this.setCallback = (callback)=>{
        emptyCallback = callback;
    };

    this.add = (url) => {
        const t = new task(url, ()=>{
            ret.push(t)
            finish(t);
        }, ()=>{
            finish(t);
        })
        wait.push(t);
        check(); // 每次添加触发检查
    }

    function finish(task) {
        let index = -1;
        for (let i in pool) {
            if (task.key === pool[i].key) {
                index = i;
                break;
            }
        }
        if (index >= 0) {
            pool.splice(index, 1);
            console.log(task.url, "结束啦");
            check(); // 每当有任务结束, 触发检查
        }
    }

    function check() {
        // 检查wait, 看看有没有等待任务, 检查pool, 看是否有空位
        if (wait.length > 0 && pool.length < maxNum) {
            // 有空位, 补位
            pool.push(wait.shift())
        }
        // 消费
        for (let task of pool) {
            if (task.status === "pending") {
                task.run();
            }
        }
        if (pool.length === 0) {
            // 触发任务清空回调
            console.log("任务清空")
            const r = ret.sort((x, y) => x.key - y.key)
            console.log(r)
            emptyCallback && emptyCallback(r);
            ret = [];
            count = 0;
        }
    }
}

function multiRequest(urls, maxNum) {
    const m = new multi(maxNum);
    for (let url of urls) {
        m.add(url)
    }
    m.setCallback((rets)=>{
        for (let ret of rets) {
            console.log(ret);
        }
    })
}

multiRequest(["000",'111','222','333'], 2);

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

旭日东升、

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值