使用Promise.any处理前端请求高并发之前,首先要弄清楚Promise几个函数的关系;
Promise.all(): 全部子实例(promise对象)成功才算成功,一个子实例失败就算失败
Promise.any(): 有一个子实例(promise对象)成功就算成功,全部子实例失败才算失败
Promise.race(): race是竞赛的意思,即看最先的promise子实例是成功还是失败,则它就与最先的子实例状态相同。
Promise.allSettled(): 所有子实例状态都返回结果,不管子实例是成功还是失败,包装实例才执行,不过状态总是变成成功 。
class PromisePool{
constructor(limit, callback){
this.limit = limit; // limit为每次的并发量
this.pool = []; //初始化并发池
this.callback = callback; //所有任务执行完的回调
this.urls = []; //urls地址为所有的请求地址数组
}
start(urls){
console.time('计时')
// 首次初始化并发池
this.urls = urls;
let len = Math.min(this.urls.length, this.limit);
let initUrl = this.urls.splice(0, len); //切割之后urls还剩len之后的部分
if (initUrl.length > 0) {
// 首次把线程池塞满
for (let i = 0; i < initUrl.length; i++) {
this.runTask(initUrl[i])
}
}
}
// 再次往线程池添加任务
raceTask(race){
race.then(res => {
if (this.urls.length > 0) {
let url = this.urls.shift();
// 一有一个任务完成,就再塞下一个
this.runTask(url);
}
});
}
runTask(url){
let task = this.mockFetch(url);
// this.pool里面的是promise任务数组
if(this.pool.length < this.limit) {
this.pool.push(task)
}
console.log(this.pool)
// 利用promise.any方法获取某个任务完成的信号
let race = Promise.any(this.pool);
// 每个请求结束后,将该promise请求从并发池移除
// 成功和失败都要执行移除和往并发池添加的动作
task.then((res) => {
// console.log('成功:',res);
this.pool = this.pool.filter((ele) => ele != task);
this.raceTask(race);
if (this.pool.length === 0) {
this.callback('执行完了');
console.timeEnd('计时')
}
}).catch((err) => {
// console.log('错误:',err)
this.pool = this.pool.filter((ele) => ele != task);
this.raceTask(race);
if (this.pool.length === 0) {
this.callback('执行完了');
console.timeEnd('计时')
}
})
}
// 模拟ajax请求
mockFetch(param){
return new Promise((resolve, reject) => {
setTimeout(() => {
if(param.info !== '2'){
resolve(param);
} else{
reject(param);
}
}, 2000);
})
}
}
const pool = new PromisePool(5, (res) => {
console.log(res)
});
const urls = [{
info: '1',
time: 2000
},
{
info: '2',
time: 1000
},
{
info: '3',
time: 2000
},
{
info: '4',
time: 2000
},
{
info: '5',
time: 3000
},
{
info: '6',
time: 1000
},
{
info: '7',
time: 2000
},
{
info: '8',
time: 2000
},
{
info: '9',
time: 3000
},
{
info: '10',
time: 1000
},
{
info: '11',
time: 1000
},
{
info: '12',
time: 2000
},
{
info: '13',
time: 2000
},
{
info: '14',
time: 3000
},
{
info: '15',
time: 1000
},
{
info: '16',
time: 1000
},
{
info: '17',
time: 2000
},
{
info: '18',
time: 2000
},
{
info: '19',
time: 3000
},
{
info: '20',
time: 1000
}
]
pool.start(urls);