浏览器与Node的事件循环

JavaScript是单线程语言,但是同样需要处理异步情况,如浏览器中用户交互、Node环境IO操作、异步请求等。为了实现异步编程,JavaScript的解决方法是使用事件循环进行任务队列区分。

主线程

JavaScript是单线程语言,执行程序代码只能在唯一的主线程中进行。但是运行环境如浏览器或Node? 是支持多线程的。同步代码在主线程中运行,遇到异步代码执行,但是并不等待结果,而是将任务由运行环境进行管理监控。当异步任务完成后,会加入事件队列,等待主线程通过事件循环不断处理异步任务的后续。
异步任务会被细分为宏任务和微任务进行区分。主线程会首先从微任务对列中取得事件处理。直到微任务队列尾空时,才会从宏任务对类中区任务执行。
浏览器和Node环境下的线程有所不同。

浏览器环境

事件任务

常见微任务:
1.Promise
2.MutaionObserver
常见宏任务:
1.script (可以理解为外层同步代码)
2.setTimeout/setInterval
3.UI rendering/UI事件
4.postMessage、MessageChannel
5.requestAnimationFrame

事件循环

事件循环
浏览器一般是多进程多线程的。
多进程包括浏览器的browser主进程、GPU进程、渲染Render进程(即常说的浏览器内核,与一个页面相关)、插件进程。
而对于一个页面来说的渲染进程,又可以分为多个线程,如下图。其中JS引擎线程一个页面对应一个。

浏览器页面线程

浏览器线程

GUI线程

负责渲染浏览器界面,GUI更新会被保存在一个队列中等到JS引擎空闲时立即被执行,当界面需要重绘或由于某种操作引发的reflow回流时,该线程就会执行。

js引擎线程

也称为JS内核,负责处理JavaScript脚本程序,JS引擎一直等待着任务队列中任务的到来,然后加以处理,一个Tab页中无论什么时候都只有一个JS线程在运行JS程序

定时触发器线程 (多个定时器时是否会有多个定时触发线程)

传说中的setInterval与setTimeout所在线程, 计数线程,浏览器定时计数器并不是由JS引擎计数的。

事件触发线程:管理维护事件/消息/任务队列

属于浏览器而不是JS引擎,当JS引擎执行代码块如setTimeOut时(也可来自浏览器内核的其他线程,如鼠标点击、AJAX异步请求等),会将对应任务添加到事件线程中。当对应的事件符合触发条件被触发时,该线程会把事件添加到待处理队列的队尾,等待JS引擎的处理。

异步http请求线程

XMLHttpRequest在连接后是通过浏览器新开的一个线程请求。当检测到状态更新时,如果没有设置回调函数,异步线程就产生状态
变更事件,将这个回调再放入事件队列中,等待JS引擎执行。

Node环境

Node事件循环

事件任务

Node中的事件任务划分更加详细
微任务对应有:
next tick queue:process.nextTick
other queue:Promise的then回调、queueMicrotask
宏任务对应有:
timer queue:setTimeout、setInterval
poll queue:IO事件
check queue:setImmediate
close queue:close事件
其执行顺序为:
next tick microtask queue
other microtask queue
timer queue
poll queue
check queue
close queue
执行顺序与Node事件循环中事件循环的的具体划分有关系。
而process.nextTick不属于事件循环周期中,而是在上一个事件循环结束后和下一个循环开始前,找了一个时间插入。具体来说,是在主线程为空,取微任务前就执行?

事件循环

Node的事件循环由libuv事件。libuv下的事件循环:
libuv事件循环
libuv将事件循环Event Loop划分为6个阶段,每个阶段都是一个队列。
Node事件循环阶段

  1. 微任务阶段:处理微任务的回调,优先于所有宏任务。
  2. 定时器检测阶段(timers):本阶段执行 timer 的回调,即 setTimeout、setInterval 里面的回调函数
  3. I/O事件回调阶段(I**/Ocallbacks**):执行延迟到下一个循环迭代的 I/O 回调,即上一轮循环中未被执行的一些I/O回调
  4. 闲置阶段(idle,prepare):仅系统内部使用
  5. 轮询阶段(poll):检索新的 I/O 事件;执行与 I/O相关的回调(几乎所有情况下,除了关闭的回调函数,那些由计时器和 setImmediate() 调度的之外),其余情况 node将在适当的时候在此阻塞
  6. 检查阶段(check):setImmediate() 回调函数在这里执行
  7. 关闭事件回调阶段(closecallback):一些关闭的回调函数,如:socket.on(‘close’, …)
    具体流程图:
    在这里插入图片描述

Node线程

Node环境线程
Node环境一般有7个线程:
1 个 Javascript 主线程用于执行用户代码
1 个 watchdog 监控线程用于处理调试信息
1 个 v8 task scheduler 线程用于调度任务优先级,加速延迟敏感任务执行
4 个 v8 线程用来执行代码调优与 GC 等后台任务
若有异步操作,libuv则会开启一个线程池,里面默认会有4个线程(可更改)。共11个线程。
Node11个线程
有什么想说的欢迎评论

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

晨灰ash2

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值