为什么 NodeJS http 服务器不会在无限循环中超时?

Why does a NodeJS http server not time out in an infinite loop?

我将 NodeJS http 服务器超时设置为 10 秒:

const httpServer = require('http').createServer(app);
httpServer.timeout = 10 * 1000;

对服务器的传入请求按预期在 10 秒后超时 运行 20 秒超时:

await new Promise(resolve => setTimeout(resolve, 20000));

当后端请求需要 20 秒时,服务器也会按预期超时,例如至:

http://httpstat.us/200?sleep=20000

但是运行死循环时不超时:

while(true) {}

这是为什么?

当您 运行 进入无限循环时,Javascript 中的其他事件都不能 运行。事件循环被阻塞。所以,连控制超时的定时器也不行运行。这是因为 Javascript 运行 在单个线程中使用您的 JS,而 setTimeout() 之类的东西是事件驱动的,而不是先发制人的。因此,如果您处于无限循环中,则事件循环无法处理任何事件,并且 setTimeout() 永远不会触发,这通常会导致 http 超时。

欢迎使用 node.js 的事件驱动架构。

而且,以防万一你想知道,这个:

while(true) {}

也会停止 node.js 中的所有其他 activity,而不仅仅是计时器。唯一可以 运行 的是工作线程,但在事件循环被阻塞的情况下,它们甚至无法与主线程通信。

仅供参考,您可以使用以下内容自行演示:

let start = Date.now();

function time() {
    let delta = (Date.now() - start) / 1000;
    return delta.toFixed(3);
}

console.log(`${time()}: Starting 500ms timer`)

// set timer for 500ms
setTimeout(() => {
   console.log(`${time()}: timer callback called`);
}, 500);

// spin for 3 seconds
while (Date.now() - start < 3000) {}

console.log(`${time()}: finished while loop`);

您可以非常清楚地看到计时器在 while 循环结束之前不会触发。虽然计时器应该在 500 毫秒后触发,但直到 3 秒 while 循环完成后它才会处理其回调。

您可以在 settimeout 函数中调用相同的函数,而不是在无限 while 循环中调用 运行

const loop = () => {
setTimeout(() => {
    console.log("TCS")
    loop()
}, 5000);
}

loop()

我在模板引擎处理 circ 时遇到了类似的问题。用户数据中的引用。

我想出的解决方案绝对是 hack。但只要你能让事情异步,就有可能解决这个问题。

通过稍微调整 jfriend00 的代码,它可以按预期工作:

let start = Date.now();

function time() {
    let delta = (Date.now() - start) / 1000;
    return delta.toFixed(3);
}

console.log(`${time()}: Starting 500ms timer`)

// set timer for 500ms
setTimeout(() => {
   console.log(`${time()}: timer callback called`);
}, 500);

function breath() {
    return new Promise(resolve => setImmediate(resolve));
}

async function main() {
    // spin for 3 seconds
    while (Date.now() - start < 3000) {
        await breath();
    }
}

console.log(`${time()}: finished while loop`);

您可以将其更改为仅在 1% 的时间内呼吸或其他不会对性能造成太大影响的东西。