1.Promise.all

const parallelRun = async max => {
const requestSliceList = [];
for (let i = 0; i < requestList.length; i += max) {
requestSliceList.push(requestList.slice(i, i + max));
}

for (let i = 0; i < requestSliceList.length; i++) {
const group = requestSliceList[i];
try {
const res = await Promise.all(group.map(fn => fn()));
console.log('接口返回值为:', res);
} catch (error) {
console.error(error);
}
}
};

但是如果中间有一次请求失败了 Promise.all就失败了。不需要判断返回值的情况可行。

2.Promise.allSettled

const parallelRun = async max => {
const requestSliceList = [];
for (let i = 0; i < requestList.length; i += max) {
requestSliceList.push(requestList.slice(i, i + max));
}

for (let i = 0; i < requestSliceList.length; i++) {
const group = requestSliceList[i];
try {
// 使用 allSettled 替换 all
const res = await Promise.allSettled(group.map(fn => fn()));
console.log('接口返回值为:', res);
} catch (error) {
console.error(error);
}
}
};

能解决其中一个接口出错,返回值会记录成功还是失败。但是不能解决其中有一个接口非常耗时的时候,阻塞后续并发。

3.最优解

type QueueItem<T extends (...args: any | any[]) => any> = {
fn: T;
params: Parameters<T> | never[];
cb?: (res: ReturnType<T>) => void;
};
class RequestQueue {
max: number;
runingCount: number;
queue: QueueItem<any>[];
constructor({ count = 6 }) {
this.max = count;
this.runingCount = 0;
this.queue = [];
}
add<T extends (...args: any[]) => any, P extends Parameters<T>[0]>(
fn: T,
params?: Parameters<T> extends []
? (res: ReturnType<T>) => void
: P extends undefined
? Parameters<T>
: P,
cb?: Parameters<T> extends [] ? never : (res: ReturnType<T>) => void,
) {
this.queue.push({
fn,
params: params
? Array.isArray(params)
? params
: [params]
: typeof fn === 'function'
? []
: [],
cb: typeof params === 'function' ? params : cb,
});
// console.log('addQueue:', this.queue, this.queue.length, this.runingCount, this.max);
this.run();
}
async run() {
if (this.queue.length > 0 && this.runingCount < this.max) {
this.runingCount++;
const { fn, params, cb } = this.queue.shift()!;
try {
const res = await fn(...params);
cb?.(res);
} finally {
this.runingCount--;
this.run();
}
}
}
}

export default new RequestQueue({ count: 6 });


使用
import RequestQueue from '/@/utils/RequestQueue';
const composite = ref<any>([]); //与dataTypeList同格式
const dataTypeList = [{
list: [],
code: 'enterprise',
loading: true,
},{
list: [],
code: 'expert',
loading: true,
},{
list: [],
code: 'policy',
loading: true
}]
const apis = {
enterprise: dataSearchApi.getNewEnterpriseListByPage, // Promise实例
expert: 'xxxx',
policy: 'xxxx',
}
for (const item of dataTypeList) {
const params = {
pageNo: 1,
pageSize: 10
}
const api = apis[item.code];
if (api) {
try {
RequestQueue.add(api,[params],(res) => {
if (res.code === '00000') {
const index = composite.value?.findIndex((i) => i.code === item.code);
console.log('index', index);
if (index !== void 0) {
composite.value![index].list = res.data?.rows as any;
composite.value![index].loading = false;
}
}
})
} catch(error) {
console.error(`请求失败: ${item.code}`, error);
}
}
}

其他优秀库的解决方案

npm install p-limit -S

使用方法

import plimit from 'p-limit';


const limit = plimit(10);

requestList.forEach(async item => {
const res = await limit(item);
console.log(res);
});