File size: 2,368 Bytes
dbb1bf9 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 | type LayoutBatchCallback = () => void;
export type CancelLayoutBatch = () => void;
interface QueuedCallback {
callback: LayoutBatchCallback;
cancelled: boolean;
}
const measureQueue: QueuedCallback[] = [];
const mutateQueue: QueuedCallback[] = [];
let scheduled = false;
let flushing = false;
function requestFrame(callback: FrameRequestCallback): void {
const raf =
typeof window !== 'undefined' && typeof window.requestAnimationFrame === 'function'
? window.requestAnimationFrame.bind(window)
: typeof globalThis.requestAnimationFrame === 'function'
? globalThis.requestAnimationFrame.bind(globalThis)
: undefined;
if (raf) {
raf(callback);
return;
}
setTimeout(() => callback(Date.now()), 0);
}
function scheduleFlush(): void {
if (scheduled || flushing) return;
scheduled = true;
requestFrame(flushQueues);
}
function enqueue(queue: QueuedCallback[], callback: LayoutBatchCallback): CancelLayoutBatch {
const entry: QueuedCallback = { callback, cancelled: false };
queue.push(entry);
scheduleFlush();
return () => {
entry.cancelled = true;
};
}
function reportLayoutBatchError(error: unknown): void {
if (typeof globalThis.reportError === 'function') {
globalThis.reportError(error);
return;
}
setTimeout(() => {
throw error;
}, 0);
}
function flushQueue(queue: QueuedCallback[]): void {
const errors: unknown[] = [];
for (const entry of queue) {
if (entry.cancelled) continue;
try {
entry.callback();
} catch (error) {
errors.push(error);
}
}
for (const error of errors) reportLayoutBatchError(error);
}
function flushQueues(): void {
scheduled = false;
flushing = true;
try {
const measures = measureQueue.splice(0);
flushQueue(measures);
const mutates = mutateQueue.splice(0);
flushQueue(mutates);
} finally {
flushing = false;
if (measureQueue.length > 0 || mutateQueue.length > 0) scheduleFlush();
}
}
export function __resetForTest(): void {
measureQueue.length = 0;
mutateQueue.length = 0;
scheduled = false;
flushing = false;
}
export function measure(callback: LayoutBatchCallback): CancelLayoutBatch {
return enqueue(measureQueue, callback);
}
export function mutate(callback: LayoutBatchCallback): CancelLayoutBatch {
return enqueue(mutateQueue, callback);
}
|