Timeout limitations when using process.nextTick(), promises, and queueMicrotask()


例如,以下代码由 vm.runInNewContext() 执行,超时时间为 5 毫秒,它安排了一个无限循环在 promise 解决后运行。 计划的循环永远不会被超时中断:

const vm = require('vm');

function loop() {
  while (1) console.log(Date.now());
}

vm.runInNewContext(
  'Promise.resolve().then(loop);',
  { loop, console },
  { timeout: 5 }
);

Because of the internal mechanics of how the process.nextTick() queue and the microtask queue that underlies Promises are implemented within V8 and Node.js, it is possible for code running within a context to "escape" the timeout set using vm.runInContext(), vm.runInNewContext(), and vm.runInThisContext().

For example, the following code executed by vm.runInNewContext() with a timeout of 5 milliseconds schedules an infinite loop to run after a promise resolves. The scheduled loop is never interrupted by the timeout:

const vm = require('vm');

function loop() {
  while (1) console.log(Date.now());
}

vm.runInNewContext(
  'Promise.resolve().then(loop);',
  { loop, console },
  { timeout: 5 }
);

This issue also occurs when the loop() call is scheduled using the process.nextTick() and queueMicrotask() functions.

This issue occurs because all contexts share the same microtask and nextTick queues.