You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tailchat/client/shared/utils/request.ts

90 lines
2.1 KiB
TypeScript

import _chunk from 'lodash/chunk';
import _flatten from 'lodash/flatten';
interface QueueItem<T, R> {
params: T;
resolve: (r: R) => void;
reject: (reason: unknown) => void;
}
/**
* 创建一个自动合并请求的函数
* 在一定窗口期内的所有请求都会被合并提交合并发送
* @param fn 合并后的请求函数
* @param windowMs 窗口期
*/
export function createAutoMergedRequest<T, R>(
fn: (mergedParams: T[]) => Promise<R[]>,
windowMs = 200
): (params: T) => Promise<R> {
let queue: QueueItem<T, R>[] = [];
let timer: number | null = null;
async function submitQueue() {
timer = null; // 清空计时器以接受后续请求
const _queue = [...queue];
queue = []; // 清空队列
try {
const list = await fn(_queue.map((q) => q.params));
_queue.forEach((q1, i) => {
q1.resolve(list[i]);
});
} catch (err) {
_queue.forEach((q2) => {
q2.reject(err);
});
}
}
return (params: T): Promise<R> => {
if (!timer) {
// 如果没有开始窗口期,则创建
timer = window.setTimeout(() => {
submitQueue();
}, windowMs);
}
return new Promise<R>((resolve, reject) => {
queue.push({
params,
resolve,
reject,
});
});
};
}
/**
* 创建一个自动拆分请求参数的函数
*/
export function createAutoSplitRequest<Key, Item>(
fn: (keys: Key[]) => Promise<Item[]>,
type: 'serial' | 'parallel',
limit = 100
): (arr: Key[]) => Promise<Item[]> {
return async (arr: Key[]): Promise<Item[]> => {
const groups = _chunk(arr, limit);
if (type === 'serial') {
const list: Item[] = [];
for (const group of groups) {
const res = await fn(group);
if (Array.isArray(res)) {
list.push(...res);
} else {
console.warn('[createAutoSplitRequest] fn should be return array');
}
}
return list;
} else if (type === 'parallel') {
const res = await Promise.all(groups.map((group) => fn(group)));
return _flatten(res);
}
return [];
};
}