浏览器事件循环

浏览器事件循环

浏览器有哪些进程和线程

浏览器是一个多进程多线程的应用程序

为了避免相互影响,减少连环崩坏的几率,当启动浏览器后,会自动启动多个进程
在这里插入图片描述

像其中的浏览器进程,GPU进程,网络进程,渲染进程 等等

最主要是浏览器进程,网络进程 及渲染进程

浏览器进程主要工作内容

  • 界面显示:比如浏览器导航栏,标签页,等等
  • 用户交互:比如用户点击,鼠标移动,放大缩小,滚轮滚动等等
  • 子进程管理:启东其他进程等等

浏览器内部会启动多个线程处理不同的任务

网络进程的主要工作内容

负责加载网络资源,网络进程内部会启动多个线程来处理不同的网络任务。

渲染进程的主要工作内容

渲染进程启动后,会开启一个渲染主线程负责执行HTML、CSS、JS代码

默认情况下,浏览器会为每一个标签页启动一个新的渲染进程,以保证不同的标签页之间不相互影响

渲染主线程是如何工作的

渲染主线程是浏览器中最繁忙的线程,其处理的任务包括但不限于:

  • 解析HTML
  • 解析CSS
  • 计算样式
  • 布局
  • 处理图层
  • 执行全局JS代码
  • 执行事件处理函数
  • 执行计算器的回调函数
  • 绘制页面

那么如何进行任务调度呢?即如何确定任务的执行顺序呢

比如说执行一个js代码,到一半是,用户进行了点击,该如何处理呢?或者定时器到时间了又该如何处理呢?等等诸如此类的问题

渲染主线程想到一个方案:排队 如下图
在这里插入图片描述

  1. 在最开始的时候,渲染主线程会进入无限循环
  2. 每一次循环会检查消息队列中是否有任务在排队,如果有,取出第一个任务进行执行,执行完成后进入下一个循环;如果没有则进入休眠状态
  3. 其他所有线程(包括其他进程的线程)可以随时向消息队列中添加任务至队尾。在添加任务时,如果主线程是休眠状态,则会唤醒渲染主线程让它继续循环;

这样一来 就可以让每个任务都进行下去,整个过程则称之为事件循环(消息循环)

异步

在代码执行过程中,会遇到一些无法立即处理的任务。比如:

  • 计时完成后需要执行的任务:setTimeout,setInterval
  • 网络通信完成后需要执行的任务:XHR Fetch
  • 用户操作后需要执行的任务:addEventListener

如果让渲染主线程等待这些任务的时机达到,就会导致主线程长期处于阻塞的状态,从而导致浏览器卡死。如下图:

在这里插入图片描述

当遇到定时器,如果等待定时器执行完成则会阻塞渲染主线程的执行,导致消息队列中的任务无法及时得到执行,比如绘制页面等,从而导致浏览器卡死,影响用户体验。

渲染器选择使用异步的方式来解决:当他遇到计时任务时,他会告诉计时线程,你帮我记个时,当时间到了你去消息队列排个队哈,我继续干活去了

如下图:

在这里插入图片描述

面试: 如何理解JS 的异步?

JS 是一门单线程的语言, 这是因为它运行在浏览器的渲染主线程中, 而渲染主线程只有一个。渲染主线程承担着诸多的工作, 渲染页面、执行JS 都在其中运行。

如果使用同步的方式, 就极有可能导致主线程产生阻塞, 从而导致消息从列中的很多其他任务无法得到执行以。
这样一来, 一方面会导致繁忙的主线程白白的消耗时间, 另一方面导致页面无法及时更新, 给用户造成卡死现象.

所以浏览器采用异步的方式来避免。具体做法是当某些任务发生时, 比如计时器、网络, 事件监听, 主线程将任务交给其他线程去处理, 自身立即束任务的执行, 转而执行后续代码, 当其他线程完成时, 将事先传递的回调函数包装成任务, 加入到消息队列的末尾排队, 等待主线程调度执行。
在这种异步模式下, 浏览器永不阻塞, 从而大度的保证了线程的流畅运行。

任务有优先级么

任务没有优先级,在消息队列中先进先出,但消息队列有优先级

根据W3C的最新解释:

  • 每个任务都有一个任务类型,同一个类型的任务必须在一个队列,不同类型的任务可以分属与不同的队列。在每一次事件循环中,浏览器可以根据实际情况从不同的队列中取出任务执行。
  • 浏览器必须准备一个微队列,尾队列的任务优先其他所有任务执行

在目前chrome的实现中,至少包含了下面的队列:

  • 延时队列:用于存放计时器到达后的回调任务,优先级【中】
  • 交互队列:用户存放用户操作后产生的事件处理任务,优先级【高】
  • 微队列:用户存放需要最快执行的任务,优先级【最高】

加入微队列的主要方式:Promise, MutationObserver

例如:

// 将该函数加入微队列
Promise.resolve().then(函数)
// 如下代码的会输出什么
function a() {
    console.log(1);
    Promise.resolve().then(() => {
        console.log(2)
    })
}
console.log(3);

setTimeout(() => {
    console.log(4)
    a();
}, 0)

new Promise((resolve, reject) => {
    console.log(5);
    resolve()
}).then(() => {
    console.log(6)
})
/**
 * 首先将全局js代码 加入到执行队列
 * 运行到第8行时 输出3
 * 运行到第10行时 向延时队列添加一个任务(即该回调函数)
 * 运行到第16行时 输出5
 * 运行到第18行时 将then 里面的回调函数添加到 微队列
 * 全局js执行完 开始下次循环 
 * 首先查看微队列是否有任务 有 取出任务到执行队列进行执行
 * 输出6 任务结束 开始下一次循环
 * 查看微队列是否有任务 没有 -> 取出延时队列的任内到执行队列进行执行
 * 执行到11行 输出 4
 * 接着执行第3行 输出1
 * 第四行 将函数添加到微队列
 * 回调函数执行完成 开始下一次循环
 * 最后输出6
 */
356412

抖音 渡一教育 袁进老师 功底深厚 非常牛逼 推荐兄弟们去关注看他的视频

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
浏览器事件循环机制是一种执行模型,用于处理浏览器中的异步任务。它的基本原理是通过一个事件队列来管理异步任务的执行顺序,确保每个任务都能按照规定的顺序得到执行。 事件循环机制的核心是事件循环线程,它负责处理所有的异步任务。当浏览器遇到一个异步任务时,它会将任务添加到事件队列中,然后继续执行同步任务。当同步任务执行完毕后,事件循环线程会开始从事件队列中取出任务,按照顺序执行它们。 事件循环机制的另一个重要的概念是回调函数,它是异步任务完成后需要执行的函数。当浏览器取出一个任务时,它会检查该任务是否有回调函数,如果有,就执行该函数。如果没有,就直接进入下一个任务。 事件循环机制的实现还涉及到一些微任务和宏任务的概念。微任务是指在当前任务执行完毕后立即执行的任务,而宏任务则是指需要等到下一个事件循环周期才执行的任务。常见的微任务包括Promise的then()和catch()方法、MutationObserver的回调函数等,而常见的宏任务包括setTimeout、setInterval、requestAnimationFrame等。 总之,浏览器事件循环机制的原理是通过一个事件队列来管理异步任务的执行顺序,确保每个任务都能按照规定的顺序得到执行。它是浏览器中实现异步任务的核心机制,理解它对于开发高效的异步代码非常重要。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值