/* * https://github.com/morethanwords/tweb * Copyright (C) 2019-2021 Eduard Kuzmenko * https://github.com/morethanwords/tweb/blob/master/LICENSE */ 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 addHeavyTask(queue: HeavyQueue, method: 'push' | 'unshift' = 'push') { if(!queue.items.length) { return Promise.resolve([]); } queue.promise = deferredPromise(); heavyQueue[method](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) { queue.promise.resolve([]); 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.apply(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); }