浏览器事件循环

浏览器事件循环

浏览器是一个多进程多线程的应用程序
为了避免相互影响,减少连环崩坏的几率,当启动浏览器后,会自动启动多个进程(每一个标签页都会开启一个进程,所以说chrome是内存杀手)
在这里插入图片描述
主要进程包括

  1. 浏览器进程:界面显示,用户交互,子进程管理
  2. 网络进程:加载网络资源
  3. 渲染进程:会开启一个渲染主线程,处理html,css,js

渲染主线程如何工作

渲染进程要处理的事情非常多,包括但不限于

  1. 解析html
  2. 解析css
  3. 计算样式
  4. 执行js
  5. 处理事件回调函数
  6. 处理定时器函数

这么多任务渲染主线程如何调度?
在这里插入图片描述

  1. 渲染主线程会进入无限循环。

  2. 每次循环会检查消息队列中是否存在任务 --> 有则取出第1个任务执行–> 执行完进入下次循环。没有任务则进入休眠状态。

  3. 其他所有线程(包括其他进程的子线程),可以随时向消息队列的末尾添加任务。
    添加任务时,如果渲染主线程是休眠状态,则会唤醒让它继续循环取出任务执行。

注意:消息队列不止一个,常见包括 微任务(最高),交互队列(高),延时队列(中)

微任务: promise.then(),  await下面, queuemicrotask()
其他队列(宏任务):ajax,settimeout,dom监听,ui渲染

以上过程称为事件循环

异步

在执行代码时,会遇到一些无法立即处理的任务。

  • 计时器结束时需要执行的任务。—— setTimeout setInterval
  • 网络通信完成后需要执行的任务。—— XHR Fetch
  • 用于操作后需要执行的任务。—— EventListener

如果渲染主线程一直等待这些任务的时间点到来,那就会一直处于阻塞的状态,表现为浏览器卡死。

浏览器选择用异步来解决这个问题。这样渲染主线程永不阻塞。

在这里插入图片描述

同步 JS 为什么会阻塞渲染
因为 js 运行在渲染主线程中,所以是单线程的语言。而渲染主线程有许多的工作,包括渲染页面和执行全局 js。

问题

1,如何理解js异步
因为 js 运行在渲染主线程中,所以是单线程的语言。而渲染主线程有许多的工作,包括渲染页面和执行全局 js。

如果使用同步的方式,大概率会造成渲染主线程阻塞,进而导致消息队列中的很多其他任务无法及时执行。表现为页面无法及时更新,给用户造成浏览器卡死的现象。

所以浏览器采用异步的方式来避免这个问题。具体做法:

当有某些任务产生后,计时器,网络通信,事件监听等,渲染主线程会交给其他对应线程去处理,自身继续执行后面的代码。当其他线程处理完成后,会将实现传递的回调函数包装为任务,发送到消息队列末尾,等待渲染主线程调度执行。

在这种异步模式下,浏览器不会被阻塞,最大限度的保证了单线程的流畅运行。
2,讲一下 js 的事件循环
事件循环又叫做消息循环,是浏览器渲染主线程的工作方式。

在 Chrome 的源码中,会开启一个不会结束的 for 循环for(;😉{},每次循环从消息队列中取出第1个任务执行,其他线程将产生的任务加入到消息队列末尾即可。

过去把消息队列简单的分为微队列和宏队列。现在已经无法满足现代浏览器的复杂环境了。

根据 W3C 的解释,每个任务都有类型,同类型的任务必须在同一个队列,不同的任务可以属于不同的队列。而不同队列的优先级也不一样。

一次事件循环中,由浏览器来决定调取那个队里中的任务。同时必须有一个优先级最高的微队列,必须优先调度执行。
3,js 能做到精准计时吗
不能。

1,受事件循环的影响,计时器的回调函数所在的延时队列优先级较低,这样即便倒计时结束,也得等某些队列的任务执行完成,所以会带来偏差。

2,W3C 的标准,浏览器实现的倒计时,如果嵌套超过5层,默认会有 4ms 的最少时间,这也是可能的偏差。

3,操作系统的计时函数本身就有少量误差,js 计时器调用的就是它,所以也会有偏差。

4,计算机硬件没有原子钟,无法做到精准计时。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值