mirror of https://github.com/msgbyte/tailchat
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.
90 lines
2.1 KiB
TypeScript
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 [];
|
|
};
|
|
}
|