首页 > 解决方案 > 节点:在跟踪它运行多长时间的同时,每秒一致地运行函数 X 次

问题描述

我想编写一个自动化最大的系统。8192 个不同的值,每秒持续 40 次。我想做的那种自动化是例如​​让一些值形成一个从 0 到 255 的正弦曲线,其他的从 50 上升到 80,其他的在 255 和 0 之间切换等等。

我需要知道每次执行需要多长时间,如果执行时间超过允许的时间,它应该“丢帧”。

我的第一种方法是

// simplified code
const fps = 40
const executionStats : number[] = []
executionStats.length = fps * 10

const startFrame = new Date()

type SingleValue = {current: number, effectType: string, effectStarted: number}
const values : SingleValue[] = [...] // up to 8192 entries

// this is calculating the target value based on some lookups in other objects
// and based on when the effect started and in what tick we are in right now
const runSingleEffect = (value: SingleValue, tick: number) : number => {...}

const handler = async (tick: number) => {
   values.forEach(value => {value.current = runSingleEffect(value, tick)})
}

setInterval(async () => {
   const start = new Date()
   await handler((start - startFrame) / fps);
   const end = new Date()
   executionStats.push(end - start)
   executionStats.unshift()
}, 1000 / fps)

有没有比使用简单的更好的方法setInterval?(显然我可以为执行统计使用环形缓冲区)但是有没有更好的方法来确保一次只运行一个处理程序?可能有那种东西的图书馆吗?

标签: node.jstypescriptsetinterval

解决方案


我会使用setTimeout连续重新订阅。您将在每个“循环”结束时重新计算下一个刻度。

function defer (ms) {
    const frameBudgetMs = 1000 / fps;
    setTimeout(async () => {
        const start = Date.now();
        try {
            await handler((start - startFrame) / fps);
        } finally {
            const end = Date.now();
            const ms = end - start;
            executionStats.push(ms);
            executionStats.unshift();

            // a) In case we are over our frame, start next defer immediately.
            let nextTickMs = Math.max(0, frameBudgetMs - ms);
            defer(nextTickMs);

            // b) In case we want to execute at specific frame interval, but just dropping the frames
            let nextTickMs = frameBudget - ms % frameBudget;
            defer(nextTickMs);
        }
    }, ms)
}

// start our loop
defer(0);

如您所见,您在重新订阅场景中是完全灵活的,在这样的“循环”中不可能有并行运行。


推荐阅读