Promise が同時実行を制御する方法

問題の背景

あるプロジェクトページは非常に複雑で、ページの初期化に入ると大量の http リクエストが生成され、同時リクエストが多すぎてコール スタックのメモリ オーバーフローが発生し、ページがクラッシュする可能性があります。同時に要求する数を制限する必要があります。

実現方法

方法1

//自定义请求函数
const request = url => {
    return new Promise(resolve => {
        setTimeout(() => {
            resolve(`请求${url}完成`)
        }, 1000)
    }).then(res => {
        console.log('外部逻辑', res);
    })
}

//添加请求
const addRequest = (url) => {
    let requestTask = request(url);
    container.push(requestTask); 
    requestTask.then(res => {
        //请求结束后将该Promise任务从并发池中移除
        pool.splice(container.indexOf(requestTask), 1);
        console.log(`${url} 结束,当前并发数:${container.length}`);
        url = urls.shift();
        //每当并发池完成一个任务,同时添加一个任务
        if(url !== undefined){
            addRequest(url);
        }
    })
}

let requestUrls =  ['xxx1.com','xxx2.com','xxx3.com','xxx4.com','xxx5.com','xxx6.com','xxx7.com'] // 请求地址
let container = []//并发请求容器
let max = 3 //最大并发请求数量
//先循环把并发池塞满
while (container.length < max) {
    let requestUrl = requestUrls.shift();
    addTask(requestUrl)
}

方法 2

//自定义请求函数
const request = url => {
    return new Promise(resolve => {
        setTimeout(() => {
            resolve(`请求${url}完成`)
        }, 1000)
    }).then(res => {
        console.log('外部逻辑', res);
    })
}

//添加请求任务
const addTask = (url) => {
    let task = request(url);
    pool.push(task); 
    task.then(res => {
        //请求结束后将该Promise任务从并发池中移除
        pool.splice(pool.indexOf(task), 1);
        console.log(`${url} 结束,当前并发数:${pool.length}`);
    })
}
每当并发池完成一个任务,同时添加一个任务
const run = (hasFinishTask) => {
    hasFinishTask.then(res => {
        let url = requestUrls.shift();
        if(url !== undefined){
            addTask(url);
            run(Promise.race(container));
        }
    })
}

let requestUrls =  ['xxx1.com','xxx2.com','xxx3.com','xxx4.com','xxx5.com','xxx6.com','xxx7.com'] // 请求地址
let container = []//并发请求容器
let max = 3 //最大并发请求数量
//先循环把并发池塞满
while (container.length < max) {
    let requestUrl = requestUrls.shift();
    addTask(requestUrl)
}
//利用Promise.race方法来获得并发池中某任务完成的信号
let hasFinishTask = Promise.race(container)
run(hasFinishTask)

最後に書く

上記の 2 つの方法の違いは、2 番目の方法が Promise.race() メソッドを使用して並行プール内のタスクの完了のシグナルを取得し、タスクを削除し、タスクを再度追加することです。 2 つの方法は次のとおりです。

  • 配列を初期化して同時リクエストを格納する

  • 最大同時実行変数を初期化する

  • ループは配列を同時リクエストで埋めます

  • 各リクエストが開始された後、このリクエストを削除し、新しいリクエストを同時リクエストの配列に追加します

以上がPromiseの同時リクエスト実現の考え方です. 他の実装方法がありましたら, 交換用にメッセージを残していただければ幸いです.

おすすめ

転載: blog.csdn.net/qq_44588612/article/details/128626581