关于javascript:在setTimeout()函数之后调用setImmediate()函数

setImmediate() function is called after setTimeout() function

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

setImmediate() function schedules"immediate" execution of callback
after I/O events' callbacks and before timers set by setTimeout and
setInterval are triggered.

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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
2
3
4
5
6
7
TIMEOUT FIRED
1
4
2
3
5
6

我写了另一个示例,并且setTimeout也在setImmediate之前起作用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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
4
5
6
7
TIMEOUT-1 FIRED
TIMEOUT-2 FIRED
TIMEOUT-1 FIRED
TIMEOUT-2 FIRED
1
2
3


让我们将上面的示例编写如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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
4
5
6
7
1
2
3
TIMEOUT-1 FIRED
TIMEOUT-2 FIRED
TIMEOUT-1 FIRED
TIMEOUT-2 FIRED

说明:

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 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周期内移动这两个调用,则始终首先执行立即回调:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 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

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

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