/** * 包装一个限制速率执行的函数 * @description 例如在 1 秒内执行最多执行 5 次, * * @param fn 原函数 * @param options.limit 限制次数 * @param options.delay 限制时间 ms * @param options.maxWaitCount 最大等待计数,如果超过的执行会被拒绝 * * @example * const limitedFn = limitQueue(async (x) => {}) * await limitedFn(1) * await limitedFn(2) * */ export function limitQueue any>( fn: T, options: { limit: number delay: number maxWaitCount?: number } ): T { let queue: [any[], (value: any) => any, (value: any) => any][] = [] let countList: boolean[] = [] let { limit, delay, maxWaitCount } = options let finFn = (...args: any[]) => { return new Promise((resolve, reject) => { if (maxWaitCount && queue.length >= maxWaitCount) { reject(new Error(`err_limitQueue_maxWaitCount:${queue.length}`)) return } queue.push([args, resolve, reject]) tick() }) } async function tick() { if (queue.length > 0) { if (countList.length >= limit) { return } else { let task = queue.pop() if (task) { countList.push(true) let resolve = task[1] let reject = task[2] let re try { re = await (fn as any).apply(null, task[0]) } catch (e) { reject(e) } resolve(re) setTimeout(() => { countList.pop() tick() }, delay) } } } } return finFn }