当前位置: 首页 > 后端技术 > Node.js

深入理解事件循环机制

时间:2023-04-03 20:38:40 Node.js

微信公众号:【前端一锅菜】一点技术,一点思考。有问题或建议,欢迎留言公众号。前面的问题:单线程的时候js怎么异步呢?事件循环的过程是怎样的?什么是宏任务和微任务,它们有何不同?node.js的事件循环是什么,它和浏览器的事件循环有什么区别?进程与线程浏览器是多进程的,具体包括的进程有:浏览器进程:浏览器的主进程(负责协调和主控),只有一个;第三方插件进程:每类插件对应一个进程,仅在使用该插件时才创建;GPU进程:最多一个,用于3D绘图;浏览器渲染进程(内核):默认一个tab页一个进程,相互独立,控制页面渲染,脚本执行,事件处理等(有时会优化,比如多个空白tab会合并成一个进程).其中,浏览器渲染进程是前端页面主要使用的进程,包含的线程有:GUI渲染线程(负责渲染页面,解析HTML,CSS形成DOM树,JS引擎互斥)JS引擎线程事件触发线程定时器触发线程Http请求线程等主线程关于执行中的线程:主线程:即js引擎执行的线程。只有一个线程,页面渲染和功能处理都在这个主线程上执行。工作线程:又称后台线程,该线程可能存在于浏览器或js引擎中,与主线程分离,处理文件读取、网络请求等异步事件。事件循环中的所有任务可以分为同步任务和异步任务。同步任务,顾名思义,就是立即执行的任务。同步任务一般直接进入主线程执行。异步任务就是异步执行的任务,比如ajax网络请求、setTimeout定时函数等都是异步任务,异步任务会通过任务队列机制(先进先出机制)进行协调。同步和异步任务进入不同的执行环境,同步进入主线程,即主执行栈,异步进入任务队列。主线程中的任务执行完后为空,会去任务队列中读取对应的任务,推送到主线程中执行。以上过程的不断重复就是我们所说的EventLoop(事件循环)。在事件循环中,每个循环操作称为tick,其关键步骤可以概括为:一开始,将整个脚本作为宏任务执行,执行过程中直接执行同步代码,宏task进入宏任务队列,微任务进入微任务TaskQueue当前宏任务执行完出队,读取微任务列表,依次执行,直到全部执行完毕。读取宏任务列表,依次执行,直到全部执行完。有WebWorker任务,也有本轮宏任务,返回第2步,继续循环,直到宏任务和微任务队列为空。宏任务和微任务JS引擎将所有任务分为两类,一类称为宏任务(macrotask),一类称为微任务(microtask)。宏任务主要包括:js(整体代码)I/O、UI渲染MessageChannel、postMessagesetImmediate(Node.js环境)setTimeout、setIntervalrequestAnimationFrame属于GUI引擎,发生在渲染过程的重绘重排部分,执行之前的微任务UI渲染主要包括:process.nextTick(Node.js环境)MutaionObserver(浏览器环境)Promise在执行macrotasks之前先执行microtasks。Node.js的事件循环事件循环是Node.js处理非阻塞I/O操作的机制。今天的大多数内核都是多线程的,这意味着它们在后台处理多个操作。当其中一个操作完成后,内核通知Node.js将合适的回调函数添加到轮询队列中,等待机会执行。当Node.js启动时,它会初始化事件循环,处理提供的输入脚本,它可能会调用一些异步API,调度定时器,或调用process.nextTick(),然后开始处理事件循环。以下是Node.js事件循环序列:timers:执行过期的setTimeout、setInterval回调。pendingcallbacks:挂起的回调函数,I/O回调的执行延迟到下一次循环迭代。执行某些系统操作的回调,例如TCP错误类型。idle,prepare:空闲准备,node系统内部使用。poll:检索新的I/O事件。执行I/O(例如文件、网络)的回调,除关闭、计时器和setImmediate之外的所有回调。在其余情况下,节点将在适当的时候阻塞在这里。检查:执行setImmediate回调。closecallbacks:执行close事件回调,比如socket.on('close',...),httpclose等。以上是宏任务的执行顺序。Node.js也是先执行微任务,再执行宏任务。Microtasks主要包括process.nextTick和promise,其中process.nextTick先执行。最后,JavaScript是一种单线程语言。异步操作放在事件循环队列中,等待主执行栈执行。没有专门的异步执行线程。