nodejs中怎么实现事件循环,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。
图中的每个方框被称作事件循环的一个"阶段",这6个阶段为一轮事件循环;
timers(定时器): 此阶段执行那些有setTimeout() 和 setInterval()调度的回调函数;
I/O callbacks(I/O回调):此阶段会执行几乎所有的回调函数,除了close callbacks(关闭回调) 和 那些有timers与setImmediate()调度的回调;
idle(空转),prepare: 此阶段只在内部使用;
poll(轮询): 检索新的I/O事件;在恰当的时候Node会阻塞在这个节点;
check(检查): setImmediate() 设置的回调会在此阶段被调用;
close callbacks(关闭事件的回调):
如:socket.on('close',...);此类的回调会在此阶段被调用; 在事件循环每次运行之间,Node.js会检查它是否等待异步I/O或定时器,如果没有的话就会自动关闭;
如果event loop 进入了poll阶段,且代码未设定timer,将会发生下面的情况:
如果poll queue不为空,event loop将同步的执行queue里的callback,知道queue为空,或执行的callback达到系统的上限;
如果poll queue为空,将会发生下面的情况:
如果代码已经被setImmediate()设定了callback,event loop 将结束poll阶段进入check阶段,并执行check阶段的queue(check阶段的queue是setImmediate设定的)
如果代码没有设定setImmediate(callback),event loop将阻塞在该阶段等待callbacks加入poll queue,一旦达到就立即执行;
如果event loop进入了poll阶段,且代码设定了timer:
如果poll queue进入空状态时(即poll阶段为空闲状态),event loop将阻塞在该阶段等待callbacks加入poll queue,一旦达到就立即执行;
setImmediate约定于setTimeout(cb,0)
path.resolve() 方法会把一个路径或路径片段的序列解析为一个绝对路径。
__dirname 总是指向当前文件夹的绝对路径
__filename 总是指向当前文件的绝对路径
note:
io: 浏览器线程去调用一些异步的回调
执行代码1
var fs = require('fs'); var path = require('path'); function someAsyncOperation(callback) { // 花费2ms fs.readFileSync('./read.txt', callback); } var timeoutScheduled = Date.now(); var fileReadTime = 0; setTimeout(function() { var delay = Date.now() - timeoutScheduled; console.log(`setTimeout ${delay} ms have passed since I was sheculed`); console.log('fileReaderTime', fileReadTime - timeoutScheduled); }, 10); someAsyncOperation(function() { fileReadtime = Date.now(); while (Date.now() - fileReadTime < 20) {} });
执行过程:
setTimeout和readFile先后加入io
setTimeout执行进入io;(需要10ms)
readfile执行,也进入io;(需要2ms)
2ms之后, redfile已经读取完毕,加入poll队列,此时poll为空,执行someAsyncOperation回调;
由于此回调有while,这里阻塞20ms;执行完为22ms
在10ms时,setTimeout不能执行,因为js是单线程,setTimeout一直被阻塞
执行完之后(22ms以后),poll 进入空闲状态
event loop检查timer,setTimeout回调;
执行结果:
readFile执行22ms
setTimeout执行22ms之后
执行代码2
var fs = require('fs'); var path = require('path'); function someAsyncOperation(callback) { // 花费9ms fs.readFileSync('./read.txt', callback); } var timeoutScheduled = Date.now(); var fileReadTime = 0; setTimeout(function() { var delay = Date.now() - timeoutScheduled; console.log(`setTimeout ${delay} ms have passed since I was sheculed`); console.log('fileReaderTime', fileReadTime - timeoutScheduled); }, 5); someAsyncOperation(function() { fileReadtime = Date.now(); while (Date.now() - fileReadTime < 20) {} });
执行结果
setTimeout执行:5ms
readFile执行9 ~ 29ms
执行代码3
在nodejs中,setTimeout(fn,0) === setTimeout(fn,0)
在浏览器中,setTimeout(fn,0) === setTimeout(fn,4)
setImmediate(() =>{ console.log('setImmediate') },0) setTimeout(() =>{ console.log('setTimeout') },0) // setTimeout 和 setImmediate的执行顺序不确定 // 因为event loop的启动也是需要时间的,可能执行到poll阶段时已经超过了1ms,此时setTimeout会先执行
const fs = require('fs'); const path = require('path'); fs.readFile(path.resolve(__dirname, '/read.txt'), () => { setTimeout(() => { console.log('setTimeout'); }, 0); setImmediate(() => { console.log('setImmediate'); }, 0); }); // 执行顺序是确定的, setImmediate,setTimeout
执行过程:
执行fs,第一轮主线程没有timer和setImmediate
假设readFile需要2ms,执行回调
由poll进入check,setImmediate会先调用
在第二轮的timer阶段,会执行setTimeout
关于nodejs中怎么实现事件循环问题的解答就分享到这里了,希望以上内容可以对大家有一定的帮助,如果你还有很多疑惑没有解开,可以关注亿速云行业资讯频道了解更多相关知识。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。