我对下面代码的输出感到困惑。(取自IBM developer Nodejs课程)。
'use strict'
const logger = require('../common/logger');
const { MAINLINE, START, END } = require('../common/constants');
(function mainline() {
logger.info(START, MAINLINE);
process.nextTick(() => {
logger.info('mainline:process.nextTick() says: hello!', 'MICROTASK')
});
let iteration = 0;
let intervalTimeout = setInterval(() => {
if (iteration < 3) {
setTimeout((iteration) => {
logger.info('setInterval(' + iteration + '):setTimeout() says: Timer expired!', 'TIMERS');
process.nextTick((iteration) => {
logger.info('setInterval():setTimeout(' + iteration + '):process.nextTick() says: Delimit TIMERS phase!', 'MICROTASK');
}, iteration);
}, 0, iteration);
} else {
logger.info('setInterval(' + iteration + ') says: Goodbye!', 'TIMERS');
clearInterval(intervalTimeout);
}
iteration++;
});
logger.info(END, MAINLINE)
})();产出如下:
1593574413204:INFO: MAINLINE: START
1593574413206:INFO: MAINLINE: END
1593574413207:INFO: MICROTASK: mainline:process.nextTick() says: hello!
1593574413210:INFO: TIMERS: setInterval(0):setTimeout() says: Timer expired!
1593574413210:INFO: MICROTASK: setInterval():setTimeout(0):process.nextTick() says: Delimit TIMERS phase!
1593574413211:INFO: TIMERS: setInterval(1):setTimeout() says: Timer expired!
1593574413211:INFO: MICROTASK: setInterval():setTimeout(1):process.nextTick() says: Delimit TIMERS phase!
1593574413213:INFO: TIMERS: setInterval(2):setTimeout() says: Timer expired!
1593574413213:INFO: TIMERS: setInterval(3) says: Goodbye!
1593574413213:INFO: MICROTASK: setInterval():setTimeout(2):process.nextTick() says: Delimit TIMERS phase!为什么记录器在最后定时器微任务之前记录“再见”?
发布于 2020-07-02 09:10:56
也许,如果您使用递归setTimeout而不是setInterval重写此代码,这将使所发生的事情更加清晰。
这会让你觉得
(function mainline() {
let iteration = 0;
function intervalJob() {
if (iteration < 3) {
setTimeout(timeoutJob, 0, interation);
// reproduce what setInterval does using recursive setTimeout
setTimeout(intervalJob, 0);
}
else {
logger.info('setInterval(' + iteration + ') says: Goodbye!', 'TIMERS');
}
iteration++;
}
function timeoutJob(iteration) {
logger.info('setInterval(' + iteration + '):setTimeout() says: Timer expired!', 'TIMERS');
process.nextTick(microtaskJobFromTimeout, iteration);
}
function microtaskJobFromTimeout(iteration) {
logger.info('setInterval():setTimeout(' + iteration + '):process.nextTick() says: Delimit TIMERS phase!', 'MICROTASK');
}
logger.info("START", "MAINLINE");
process.nextTick(() => {
console.log('mainline:process.nextTick() says: hello!', 'MICROTASK')
});
setTimeout(intervalJob,0);
logger.info("END", "MAINLINE")
})();基本上,在iteration到达3之前,每个intervalJob调用都会安排在下一个事件循环迭代中执行两个新任务:timeoutJob (它本身将在内部调度一个微任务)和递归intervalJob。
因为节点的事件循环首先执行所有超时作业,然后只执行所有微任务,所以在同一个事件循环迭代期间,最后一个intervalJob实际上将处于超时池中,而不是上一个timeoutJob。
因此,通常在执行timeoutJob之前,因为它是先被排定的,然后是intervalJob,因为它也在计时器池中,最后在循环重发之前执行微任务。
您可以通过无条件地从setInterval回调进行日志记录来验证这一点,输出如下:
主线:启动
主线:结束
微任务: mainline:process.nextTick()说:你好!
INTERVALJOB:无条件intervalJob日志记录
计时器: setInterval(0):setTimeout()说:计时器过期了!
INTERVALJOB:无条件intervalJob日志记录
微任务: setInterval():setTimeout(0):process.nextTick()说:分隔定时器阶段!
计时器: setInterval(1):setTimeout()说:计时器过期了!
INTERVALJOB:无条件intervalJob日志记录
微任务: setInterval():setTimeout(1):process.nextTick()说:分隔定时器阶段!
计时器: setInterval(2):setTimeout()说:计时器过期了!
定时器: setInterval(3)说:再见!
INTERVALJOB:无条件intervalJob日志记录
微任务: setInterval():setTimeout(2):process.nextTick()说:分隔定时器阶段!
请注意,这是特定于节点的行为,在浏览器中,每个任务都有自己的微任务检查点,而计划同时触发的两个定时器实际上将在两个不同的事件循环迭代中执行。
https://stackoverflow.com/questions/62669296
复制相似问题