【问题标题】:setImmediate() function is called after setTimeout() functionsetImmediate() 函数在 setTimeout() 函数之后调用
【发布时间】:2016-10-30 19:16:31
【问题描述】:

在nodejs的官方网站(https://nodejs.org/api/timers.html#timers_setimmediate_callback_arg)里有说:

setImmediate() 函数安排“立即”执行回调 在 I/O 事件的回调之后和由 setTimeout 设置的计时器之前和 setInterval 被触发。

但是在下面的代码中,setTimeout() 函数在 setImmediate() 之前执行。为什么?

setImmediate(function A() {
  setImmediate(function B() {
    console.log(1);
    setImmediate(function D() { console.log(2); });
    setImmediate(function E() { console.log(3); });
  });
  setImmediate(function C() {
    console.log(4);
    setImmediate(function F() { console.log(5); });
    setImmediate(function G() { console.log(6); });
  });
});

setTimeout(function timeout() {
  console.log('TIMEOUT FIRED');
}, 0)

结果:

超时触发 1 4 2 3 5 6

我写了另一个例子,setTimeout 也可以在setImmediate 之前工作。

setTimeout(function timeout() {
  console.log('TIMEOUT-1 FIRED');
}, 0)

setTimeout(function timeout() {
  console.log('TIMEOUT-2 FIRED');
}, 0)

setImmediate(function D() { console.log(1); });
setImmediate(function D() { console.log(2); });
setImmediate(function D() { console.log(3); });

setTimeout(function timeout() {
  console.log('TIMEOUT-1 FIRED');
}, 0)

setTimeout(function timeout() {
  console.log('TIMEOUT-2 FIRED');
}, 0)

输出:

TIMEOUT-1 被触发 TIMEOUT-2 已触发 TIMEOUT-1 被触发 TIMEOUT-2 已触发 1 2 3

【问题讨论】:

  • 在第一个节点 5.6.0 中我得到1 4 TIMEOUT FIRED 2 3 5 6
  • @metis 您使用的是什么版本的 node.js,因为某些旧版本似乎存在错误:github.com/nodejs/node-v0.x-archive/issues/6034
  • v.4.4.5 是nodejs欢迎页面大部分用户推荐的版本
  • 对我来说,最重要的是,依赖于这样的调度特性对于系统设计来说是一个非常脆弱的基础。
  • 我认为 Node 应该按照文档说明工作,但 究竟 设计师的意图并不是很清楚,而且很明显行为会有所不同。因此,我不会以依赖于这些 API 的特定平台行为的方式设计自己的软件。

标签: javascript node.js


【解决方案1】:

让我们把上面的例子写成如下:

var fs = require('fs')

fs.readFile("readme.txt",  function (){
    setTimeout(function timeout() {
      console.log('TIMEOUT-1 FIRED');
    }, 0)

    setTimeout(function timeout() {
      console.log('TIMEOUT-2 FIRED');
    }, 0)

    setImmediate(function D() { console.log(1); });
    setImmediate(function D() { console.log(2); });
    setImmediate(function D() { console.log(3); });

    setTimeout(function timeout() {
      console.log('TIMEOUT-1 FIRED');
    }, 0)

    setTimeout(function timeout() {
      console.log('TIMEOUT-2 FIRED');
    }, 0)})

输出:

1
2
3
TIMEOUT-1 FIRED
TIMEOUT-2 FIRED
TIMEOUT-1 FIRED
TIMEOUT-2 FIRED

说明:

定时器的执行顺序将根据调用它们的上下文而有所不同。如果两者都是从主模块中调用的,那么时间将受到进程性能的限制(这可能会受到机器上运行的其他应用程序的影响)。 例如,如果我们在一个 I/O 周期(即主模块)之外运行以下脚本,则两个定时器的执行顺序是不确定的,因为它受过程:

// timeout_vs_immediate.js
setTimeout(function timeout () {
  console.log('timeout');
},0);

setImmediate(function immediate () {
  console.log('immediate');
});
$ node timeout_vs_immediate.js
timeout
immediate

$ node timeout_vs_immediate.js
immediate
timeout

但是,如果您在一个 I/O 周期内移动这两个调用,则始终首先执行立即回调:

// timeout_vs_immediate.js
var fs = require('fs')

fs.readFile(__filename, () => {
  setTimeout(() => {
    console.log('timeout')
  }, 0)
  setImmediate(() => {
    console.log('immediate')
  })
})
$ node timeout_vs_immediate.js
immediate
timeout

$ node timeout_vs_immediate.js
immediate
timeout

使用 setImmediate() 优于 setTimeout() 的主要优点是,如果在 I/O 周期内调度,setImmediate() 将始终在任何计时器之前执行,与存在多少计时器无关。

欲了解更多信息,请参阅以下链接: https://github.com/nodejs/node/blob/master/doc/topics/the-event-loop-timers-and-nexttick.md

【讨论】:

  • 它只描述了主要文档中写的内容,不清楚它是如何工作的,它是如何与性能绑定的?什么意思 bound to the performance 这是主要问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-03-25
  • 2016-05-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-22
  • 2020-11-09
相关资源
最近更新 更多