securityos/node_modules/framer-motion/dist/es/frameloop/render-step.mjs

105 lines
3.4 KiB
JavaScript
Raw Normal View History

2024-09-06 15:32:35 +00:00
class Queue {
constructor() {
this.order = [];
this.scheduled = new Set();
}
add(process) {
if (!this.scheduled.has(process)) {
this.scheduled.add(process);
this.order.push(process);
return true;
}
}
remove(process) {
const index = this.order.indexOf(process);
if (index !== -1) {
this.order.splice(index, 1);
this.scheduled.delete(process);
}
}
clear() {
this.order.length = 0;
this.scheduled.clear();
}
}
function createRenderStep(runNextFrame) {
/**
* We create and reuse two queues, one to queue jobs for the current frame
* and one for the next. We reuse to avoid triggering GC after x frames.
*/
let thisFrame = new Queue();
let nextFrame = new Queue();
let numToRun = 0;
/**
* Track whether we're currently processing jobs in this step. This way
* we can decide whether to schedule new jobs for this frame or next.
*/
let isProcessing = false;
let flushNextFrame = false;
/**
* A set of processes which were marked keepAlive when scheduled.
*/
const toKeepAlive = new WeakSet();
const step = {
/**
* Schedule a process to run on the next frame.
*/
schedule: (callback, keepAlive = false, immediate = false) => {
const addToCurrentFrame = immediate && isProcessing;
const queue = addToCurrentFrame ? thisFrame : nextFrame;
if (keepAlive)
toKeepAlive.add(callback);
if (queue.add(callback) && addToCurrentFrame && isProcessing) {
// If we're adding it to the currently running queue, update its measured size
numToRun = thisFrame.order.length;
}
return callback;
},
/**
* Cancel the provided callback from running on the next frame.
*/
cancel: (callback) => {
nextFrame.remove(callback);
toKeepAlive.delete(callback);
},
/**
* Execute all schedule callbacks.
*/
process: (frameData) => {
/**
* If we're already processing we've probably been triggered by a flushSync
* inside an existing process. Instead of executing, mark flushNextFrame
* as true and ensure we flush the following frame at the end of this one.
*/
if (isProcessing) {
flushNextFrame = true;
return;
}
isProcessing = true;
[thisFrame, nextFrame] = [nextFrame, thisFrame];
// Clear the next frame queue
nextFrame.clear();
// Execute this frame
numToRun = thisFrame.order.length;
if (numToRun) {
for (let i = 0; i < numToRun; i++) {
const callback = thisFrame.order[i];
callback(frameData);
if (toKeepAlive.has(callback)) {
step.schedule(callback);
runNextFrame();
}
}
}
isProcessing = false;
if (flushNextFrame) {
flushNextFrame = false;
step.process(frameData);
}
},
};
return step;
}
export { createRenderStep };