import _chunk from 'lodash/chunk'; import _flatten from 'lodash/flatten'; interface QueueItem { params: T; resolve: (r: R) => void; reject: (reason: unknown) => void; } /** * 创建一个自动合并请求的函数 * 在一定窗口期内的所有请求都会被合并提交合并发送 * @param fn 合并后的请求函数 * @param windowMs 窗口期 */ export function createAutoMergedRequest( fn: (mergedParams: T[]) => Promise, windowMs = 200 ): (params: T) => Promise { let queue: QueueItem[] = []; 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 => { if (!timer) { // 如果没有开始窗口期,则创建 timer = window.setTimeout(() => { submitQueue(); }, windowMs); } return new Promise((resolve, reject) => { queue.push({ params, resolve, reject, }); }); }; } /** * 创建一个自动拆分请求参数的函数 */ export function createAutoSplitRequest( fn: (keys: Key[]) => Promise, type: 'serial' | 'parallel', limit = 100 ): (arr: Key[]) => Promise { return async (arr: Key[]): Promise => { 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 []; }; }