import { get } from '../utils/request'; import { PostDetail } from './type'; interface TaskCustomRunFn { (data: D[]): Promise } interface Task { data: D, count?: number, callback: (result: R) => void } export class RequestTaskQueue { private queue: Task[] = []; public oneMaxRun: number; public customRunFn: TaskCustomRunFn; private willRunNextLoop: boolean = false; constructor( customRunFn: TaskCustomRunFn, oneMaxRun = 50 ) { this.customRunFn = customRunFn; this.oneMaxRun = oneMaxRun; } /** * 将任务添加到队列中 * @param newTask data, callback2个值组成的请求任务项 */ add( newTask: Task ) { this.queue = [ newTask, ...this.queue ]; this.run() } remove(length: number) { this.queue = this.queue.slice(length); } /** * 将队列中每一项的data合并组装成一个数组,然后交给实例化时传递的customRunFn去处理 * customRunFn需要将[]格式的数组拼装成实际批量请求所需的参数结构 * 然后结合setTimeout的异步特性,根据oneMaxRun控制单次批量请求的队列长度,通过递归方式执行队列中的请求 * 在请求完成后,按照队列的顺序组装成请求结果数组,然后将结果按照数组index回传给callback处理 * @returns void */ run() { if ( this.willRunNextLoop || this.queue.length === 0 ) { return; } this.willRunNextLoop = true; setTimeout(() => { const willRunTasks = this.queue.slice(0, this.oneMaxRun); this.customRunFn( willRunTasks.map(({ data }) => data) ).then((results) => { willRunTasks.forEach(( { callback }, index ) => { callback(results[index]); }) this.willRunNextLoop = false; this.remove(willRunTasks.length); this.run(); }, () => { // 请求错误了 this.willRunNextLoop = false; this.remove(willRunTasks.length); this.run(); }); }, 0) } } const postDetailRequestTaskQueue = new RequestTaskQueue< { postId: number }, PostDetail >(async ( postIds: { postId: number }[] ) => { const res: any = await get( '//www.lofter.com/spread/copyright/activity/posts', { 'postIds[]': postIds.map(({ postId }) => postId).join(',') } ) const postsIdMap = res.data.posts.reduce((idMap, post) => { idMap[post.id] = post; return idMap; }, {}); return postIds.map(({ postId }) => postsIdMap[postId]); }, 50); export function fetchPostDetail(postId: number) { return new Promise((resolve) => { postDetailRequestTaskQueue.add({ data: { postId }, callback: resolve }) }) }