业务场景
该业务涉及到表格导入和切片上传等等,如果存在数据量较大情况下可能需要很久才能完成这个任务,那么客户一直去等待肯定是一件非常不友好的事情。所以我们需要优化并且利用到浏览器的特性可以同时发起多个请求,去减少等待时间。
方法实现有:完成进度、完成时间、区分请求成功数据和失败数据。
这里可以满足到一些基本需求,如果和你的业务还是相差甚远可以自行改造。
辅助函数
// 毫秒转换成时分秒
function nowTimeFu(milliseconds: number, joinStr: string = ':'):string {
let seconds = Math.floor(milliseconds / 1000);
let minutes = Math.floor(seconds / 60);
let hours = Math.floor(minutes / 60);
seconds %= 60;
minutes %= 60;
const padZero = (value: number) => String(value).padStart(2, '0');
return [padZero(hours), padZero(minutes), padZero(seconds)].join(joinStr);
}
主要核心代码
注意这里用到的是axios请求,如果你没有下载axios就请先 npm install axios -save
import axios, { AxiosRequestConfig, Method } from "axios";
type RequestResult<Success, Fail> = { success?: Success[], fail?: Fail[] };
interface RequestOptions {
method?: Method;
maxRequestNumber?: number;
data: RequestData[];
}
export type RequestData = {
url: string,
body?: any
}
export function concurrencyRequest<Success = any, Fail = any>(
{ data, maxRequestNumber = 5, method = 'GET' }: RequestOptions,
progress?: (res: number) => void, // 进度条
finalTime?: (str: string) => void // 最终用时
): Promise<RequestResult<Success, Fail>> {
const startTime: number = new Date().getTime(); // 请求开始时间
if (!Array.isArray(data)) return Promise.reject('urls must be an array');
if (data.length === 0) {
progress && progress(100);
finalTime && finalTime(nowTimeFu((new Date().getTime() - startTime)));
return Promise.resolve({ success: [], fail: [] });
};
return new Promise((resolve) => {
let index: number = 0, // 记录每一项请求下标
resultCount: number = 0; // 当前完成数量
const successResult: Success[] = [], // 成功结果
failResult: Fail[] = []; // 失败结果
async function _request() {
const item = data[index];
index++;
try {
// -----这一块我建议可以自行使用封装好的网络请求-------
const option: AxiosRequestConfig = {
url: item.url,
method,
};
switch (method) {
case "GET":
case "DELETE":
option['params'] = item.body || {};
break;
case "POST":
case "PATCH":
case "PUT":
option['data'] = item.body || {};
break;
}
const { data } = await axios<Success>(option);
// ------------------------------------------------
successResult.push(data);
} catch (error) {
failResult.push(error as Fail);
} finally {
resultCount++;
progress && progress(Math.floor(resultCount / data.length * 100)); // 实时监听进度结果
if (resultCount === data.length) {
resolve({ success: successResult, fail: failResult }); // 返回最终结果
finalTime && finalTime(nowTimeFu((new Date().getTime() - startTime))); // 最终用时
};
if (index < data.length) _request();
}
}
for (let i = 0; i < Math.min(data.length, maxRequestNumber); i++) {
_request();
}
});
}
如何使用方法
type Result = {
message: string,
status: string
};
function progress(num: number) {
console.log(`进度为:${num}%`);
}
function finalTime(str: string) {
console.log('最终用时: ', str);
}
(async () => {
const data: RequestData[] = [];
for (let index = 0; index < 100; index++) {
if (index === 10) {
data.push({
url: `https://xx.ceo/api/breeds/image/random`,
})
} else {
data.push({
url: `https://dog.ceo/api/breeds/image/random`,
body: { a: '11' }
})
}
}
const response = await concurrencyRequest<Result, any>({ data }, progress, finalTime);
console.log('response: ', response);
})();