Node.js setTimeout 极其不准确

Node.js extremely inaccurate setTimeout

最初,我有一段代码可以定期执行某些操作。虽然我遇到了奇怪的性能和时间问题。

我在下面的脚本中隔离了主循环

let sleepTime = 50 //milliseconds
var sleep = (ms) => new Promise(res => setTimeout(res, ms))
let state = {
    stopCalled: false,
    countLoops: 0,
    lastLoopTime: 0,
    loopDuration: 0,

    badLoops: [],
    badSleeps: []
}
let data = [1, 2, 3, 5, 1, 1, 1, 5, 1, 3, 1, 5, 4]
async function startLoop() {
    //necessary for first loopDuration
    state.lastLoopTime = Date.now() - 50

    while (true) {
        if (state.stopCalled) return
        state.countLoops++
        state.loopDuration = Date.now() - state.lastLoopTime
        state.lastLoopTime = Date.now()
        if (state.loopDuration > 100) {
            state.badLoops.push(state.loopDuration)
            console.log(`Bad loop duration: ${state.loopDuration}`)
        }

        //do some random work
        let rand = randomInteger(1, 7)
        for (let i = 0; i <data.length; i++) {
            if (data[i] === rand) continue
            data[i] = randomInteger(1, 7)
        }

        let initialTime = Date.now()
        await sleep(sleepTime)
        let actualSleepDuration = Date.now() - initialTime

        //sleep duration should be <=50 milliseconds
        if (actualSleepDuration > 100) {
            state.badSleeps.push(actualSleepDuration)
            console.log(`Bad sleep duration: ${actualSleepDuration}`)
        }
    }
}

function randomInteger(min, max) {
    return Math.round((max - min) * Math.random()) + min
}

代码的作用摘要: 手动调用 startLoop 后,它应该 运行 每 50ms 周期性地循环一次 我预计会有 +/-5 毫秒的误差,这没关系。

但是,睡眠函数/setTimeout 函数变得非常不准确最多 1 整分钟,尤其是在运行宁了一段时间后

我理解 setTimeout,如果没有阻塞代码则更准确,在这种情况下,这是唯一的脚本 运行ning,这对于为什么会有这么多延迟没有意义。

有没有更准确的方法运行一个函数?

完成了两项测试来自: 一个来自 Electron 17.0.1 另一个来自 Node JS 17.5.0 REPL .load file.js

经过大量测试,发现chrome throttles background tabs/windows from Chrome 88,这对于笔记本电脑上的网站来说非常省电

但是对于电子应用程序(使用 Chromium 引擎)来说真的很糟糕,不应该被限制。

要解决此问题,您应该将 backgroundThrottling 更改为 false,默认情况下为 true

const win = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {           
        backgroundThrottling: false,
    }
})

摘自throttling doc

这会影响所有 non-blocking javascript 计时器的 setInterval 和 setTimeout