問題の背景
あるプロジェクトページは非常に複雑で、ページの初期化に入ると大量の 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の同時リクエスト実現の考え方です. 他の実装方法がありましたら, 交換用にメッセージを残していただければ幸いです.