Javascript 为什么在Nodejs事件循环';什么有用?
我读了很多相关文件,但我还是不明白它是如何工作的Javascript 为什么在Nodejs事件循环';什么有用?,javascript,node.js,event-loop,Javascript,Node.js,Event Loop,我读了很多相关文件,但我还是不明白它是如何工作的 const fs = require('fs') const now = Date.now(); setTimeout(() => console.log('timer'), 10); fs.readFile(__filename, () => console.log('readfile')); setImmediate(() => console.log('immediate')); while(Date.now() - n
const fs = require('fs')
const now = Date.now();
setTimeout(() => console.log('timer'), 10);
fs.readFile(__filename, () => console.log('readfile'));
setImmediate(() => console.log('immediate'));
while(Date.now() - now < 1000) {
}
以及第二段代码日志
timer
immediate
我想没关系
问题:
我不明白为什么第一段代码会记录
immediate
readfile
我认为该文件已被完全读取,其回调函数在1秒后将I/O回调阶段的queque排入队列
然后我认为事件循环将移动到计时器(无)
,I/O回调(fs.readFile的回调)
,空闲/准备(无)
,轮询(无)
,检查(setImmediate的回调)
,最后按顺序关闭回调(无),但结果是setImmediate()
仍然首先运行。设置超时(()=>console.log('timer'),10);
setTimeout(() => console.log('timer'), 10);
fs.readFile(__filename, () => console.log('readfile'));
setImmediate(() => console.log('immediate'));
while(Date.now() - now < 1000) {
}
fs.readFile(u文件名,()=>console.log('readFile');
setImmediate(()=>console.log('immediate');
while(Date.now()-now<1000){
}
解释
setTimeout
计划在10毫秒后放入事件循环setImmediate
计划显示中断长进程的控制台输出setImmediate
在循环过程中打印immediate
控制台消息而循环后也会执行回调
结束控制台输出readfile
现在已存在
timer
在大约10秒后打印出来- 上述命令(循环除外)均不同步。他们 安排某事并立即执行下一个命令
- 回调函数仅在当前阻塞之后调用 行刑结束了
- 超时命令不保证在指定的时间执行 间隔保证它们将在之后的任何时间运行 间隔时间
非常具有实验性setImmediate
setImmediate()
回调会在readFile()
回调之前执行,即使当while
循环完成时,两者都准备就绪
然后我认为事件循环将依次移动到计时器(none)、I/O回调(fs.readFile的回调)、空闲/准备(none)、轮询(none)、检查(setImmediate的回调)和最后关闭回调(none),但结果是setImmediate()仍然首先运行
setTimeout(() => console.log('timer'), 10);
fs.readFile(__filename, () => console.log('readfile'));
setImmediate(() => console.log('immediate'));
while(Date.now() - now < 1000) {
}
问题是,事件循环的I/O回调阶段运行已经在事件队列中的I/O回调,但完成后不会自动放入事件队列。相反,它们只会在I/O poll
步骤中的稍后过程中放入事件队列(请参见下图)。因此,第一次通过I/O回调阶段时,还没有要运行的I/O回调,因此您不会在您认为需要时获得readfile
输出
但是,setImmediate()
回调在第一次通过事件循环时就准备好了,因此它在readFile()
回调之前开始运行
I/O回调的延迟添加很可能解释了为什么readFile()
回调发生在最后而不是setImmediate()
回调之前
以下是while
循环完成时发生的情况:
readFile()
的I/O回调。它将在本周期晚些时候收集readFile()
回调事件并将其放入I/O队列(但尚未运行)setImmediate()
回调readFile()
回调因此,对于那些不太熟悉事件循环过程的人,让我们更详细地记录代码中实际发生的事情。运行此代码时(将计时添加到输出中): 我添加了以秒为单位的计时,相对于程序启动的时间,这样您就可以看到执行的时间 下面是发生的情况:
fs.readFile()
操作启动后,其他代码继续运行setImmediate()
已注册到事件系统,并且其事件位于相应的事件队列中,其他代码将继续运行循环开始循环时
while
循环期间,fs.readFile()
完成其工作(在后台运行)。它的事件已准备就绪,但尚未在相应的事件队列中(稍后将对此进行详细介绍)而
循环完成
setTimeout(() => console.log('timer'), 10);
fs.readFile(__filename, () => console.log('readfile'));
setImmediate(() => console.log('immediate'));
while(Date.now() - now < 1000) {
}
const fs = require('fs')
let begin = 0;
function log(msg) {
if (!begin) {
begin = Date.now();
}
let t = ((Date.now() - begin) / 1000).toFixed(3);
console.log("" + t + ": " + msg);
}
log('start program');
setTimeout(() => log('timer'), 10);
setImmediate(() => log('immediate'));
fs.readFile(__filename, () => log('readfile'));
const now = Date.now();
log('start loop');
while(Date.now() - now < 1000) {}
log('done loop');
0.000: start program
0.004: start loop
1.004: done loop
1.005: timer
1.006: immediate
1.008: readfile
const fs = require('fs')
let begin = 0;
function log(msg) {
if (!begin) {
begin = Date.now();
}
let t = ((Date.now() - begin) / 1000).toFixed(3);
console.log("" + t + ": " + msg);
}
log('start program');
setImmediate(() => log('immediate'));
setTimeout(() => log('timer'), 10);
const now = Date.now();
log('start loop');
while(Date.now() - now < 1000) {}
log('done loop');
0.000: start program
0.003: start loop
1.003: done loop
1.005: timer
1.008: immediate
// timeout_vs_immediate.js
const fs = require('fs');
fs.readFile(__filename, () => {
setTimeout(() => {
console.log('timeout');
}, 0);
setImmediate(() => {
console.log('immediate');
});
});
immediate
timeout