import { CancellablePromise, deferredPromise } from "./cancellablePromise"; import { getHeavyAnimationPromise } from "../hooks/useHeavyAnimationCheck"; import { fastRaf } from "./schedulers"; type HeavyQueue = { items: any[], process: (...args: any[]) => T, context: any, promise?: CancellablePromise['process']>[]> }; const heavyQueue: HeavyQueue[] = []; let processingQueue = false; export default function pushHeavyTask(queue: HeavyQueue) { queue.promise = deferredPromise(); heavyQueue.push(queue); processHeavyQueue(); return queue.promise; } function processHeavyQueue() { if(!processingQueue) { const queue = heavyQueue.shift(); timedChunk(queue).finally(() => { processingQueue = false; if(heavyQueue.length) { processHeavyQueue(); } }); } } function timedChunk(queue: HeavyQueue) { if(!queue.items.length) return Promise.resolve([]); const todo = queue.items.slice(); const results: T[] = []; return new Promise((resolve, reject) => { const f = async() => { const start = performance.now(); do { await getHeavyAnimationPromise(); const possiblePromise = queue.process.call(queue.context, todo.shift()); let realResult: T; if(possiblePromise instanceof Promise) { try { realResult = await possiblePromise; } catch(err) { reject(err); return; } } else { realResult = possiblePromise; } results.push(realResult); } while(todo.length > 0 && (performance.now() - start) < 6); if(todo.length > 0) { fastRaf(f); //setTimeout(f, 25); } else { resolve(results); } }; fastRaf(f); //setTimeout(f, 25); }).then(queue.promise.resolve, queue.promise.reject); }