事件循环(消息循环)- EventLoop

本文详细解析了浏览器的进程模型,特别是渲染主线程的工作原理,探讨了异步编程、宏任务与微任务的区别,以及事件循环在处理定时器和事件中的作用。重点解答了关于线程使用、任务优先级、事件处理顺序和计时器精度的问题。
摘要由CSDN通过智能技术生成

浏览器的进程模型

1.进程:占有一片的内存空间,每一个应用至少有一个进程,进程之间相互独立,但是可以进行通信。一个进程至少有一个线程,所以在进程开启后会自动创建一个线程来运行代码,该线称成为主线程,主线程还可以启动更多的线程来执行代码
2.线程:是进程内的一个独立执行单元,是CPU的最小的调度单元
3.浏览器的进程类型:
(1)浏览器进程:浏览器的主进程,只有一个。
a.负责浏览器界面显示,与用户交互(上方公共按钮)
b.负责各个页面的管理,创建和销毁其他进程
c.将渲染进程得到的内存中的位图,绘制到用户界面上
d.网络资源的管理,下载
(2)第三方插件进程:每种类型的插件对应一个进程,仅当使用该插件时才创建
(3)GPU进程:最多一个,用于3D绘制
(4)浏览器渲染进程(浏览器内核),他的内部是多线程的,主要作用为页面渲染,脚本执行,事件处理
(5)网络进程:负责加载网络资源

浏览器渲染主线程工作原理

浏览器是一个多线程多进程的应用程序,浏览器渲染主线程只有一个,但是一些任务可以交给其他线程来处理(例如定时器就可以交给其他线程来处理,等到定时任务结束时,将回调函数包装成任务,放到任务队列末尾)

异步

定义:无法立即执行的函数
产生:单线程是产生异步的原因
实现:事件循环是异步的实现方式
发生异步的事件:
(1)计时器:settimeout,setinterval
(2)通信:xhr(js原生对象实现的请求)fetch(基于promise,默认使用cors,可以很好的解决跨域问题)
(3)由于用户的操作,产生的任务
优势:基于异步的方式,浏览器渲染主线程永不堵塞

宏任务微任务

宏任务、微任务皆为异步任务,它们都属于一个队列,执行完同步代码以后,先执行微任务队列,再执行宏任务队列
宏任务: script、setTimeout、setInterval、postMessage、MessageChannel、setImmediate
微任务: Promise.then、Object.observe、MutationObserver、nextTick
Chrome包含的任务队列:
(1)微队列:优先级最高(有promise,mutationobserver:监听dom变化的api)
(2)交互队列(用户的行为触发的事件):优先级高
(3)延时队列:优先级中
排队:渲染主线程(微队列-延时队列-交互队列),其他线程可以帮忙处理事件,但不会处理任务
任务队列的执行: 每个任务都有一个任务类型,同一个类型的任务必须在一个队列,不同类型的任务可以分属于不同的队列。
在一次事件循环中,浏览器可以根据实际情况从不同的队列中取出任务执行。浏览器必须准备好一个微队列,微队列中的任务优先所有其他任务执行

问题总结

1.为什么渲染进程不适用多个线程来处理页面渲染,脚本执行,事件?

(1)线程安全:如果渲染和脚本执行在多个线程中同时进行,那么可能会产生竞态条件,即两个或更多的线程同时访问和修改同一资源,导致数据不一致或死锁,还可能会出现数据泄露、内存溢出等问题
(2)复杂度:多线程模型则需要处理线程间的通信和同步,这会使实现变得更为复杂
(3)性能问题:可能导致重排和重绘,例如,一个线程可能在另一个线程还在重排或重绘时就修改了DOM,这会导致结果的不一致
(4)JavaScript本身就是单线程的,其他线程无法直接访问dom

2.js 为何会阻碍渲染进程?

(1)阻塞渲染:js 是单线程的,当浏览器在执行 JavaScript 代码时,它不能同时进行页面渲染
(2)js 中的dom事件,可能会导致重回和回流
(3)js还需要处理页面中的事件,这些事件的执行也需要时间
(4)某些js脚本可能加载时间很长,页面数据改变,有绘制任务,也需要排队
补充:优化方案a.异步加载脚本(async,defer)b.代码拆分和懒加载c.将耗时的计算任务或数据处理任务转移到后台线程Web Workers中执行d.优化dom的操作e.事件委托与防抖节流

3.任务有优先级吗?

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

4.任务队列有优先级吗?

消息队列是有优先级的,在一次事件循环中,浏览器可以自行决定从不同的队列中取出任务执行,浏览器必须准备好一个微队列,微任务中的任务优先其他任务执行(promise.then 会将任务直接放到微队列)

5.正在执行一个js函数,执行到一半的时候用户触发了一个点击事件,主线程会立即执行事件的处理函数吗?

不会,需要去排队

6.点击事件和定时器同时发生,浏览器主线程先处理哪一个?

点击事件,因为点击事件所在的队列优先级高

7.如何理解js的异步?

使用异步的方式,渲染主线程永不阻塞;
(1)JS是一门单线程的语言,这是因为它运行在浏览器的渲染主线程中,而渲染主线程只有一个。同时渲染主线程承担着诸多的工作,如渲染页面、执行JS 。如果使用同步的方式,就极有可能导致主线程产生阻塞,从而导致消息队列中的很多其他任务无法得到执行。这样一来,一方面会导致繁忙的主线程白白的消耗时间另一方面导致页面无法及时更新,给用户造成卡死现象。
(2)所以浏览器采用异步的方式来避免。具体做法是当某些任务发生时,比如计时器、网络、事件监听,主线程将任务交给其他线程去处理,自身立即结束任务的执行,转而执行后续代码。当其他线程完成时,将事先传递的回调函数包装成任务,加入到消息队列的末尾排队,等待主线程调度执行。
(3)在这种异步模式下,浏览器永不阻塞,从而最大限度的保证了单线程的流畅运行

8.什么是事件循环(消息循环)?

(1).在最开始的时候,渲染主线程会进入一个无限循环
(2).每一次循环会检查消息队列中是否有任务存在。如果有,就取出第一个任务执行,执行完一个后进入下一次循环;如果没有,则进入休眠状态。
(3).其他所有线程(包括其他进程的线程)可以随时向消息队列添加任务。新任务会加到消息队列的末尾。在添加新任务时,如果主线程是休眠状态,则会将其唤醒以继续循环拿取任务,这样一来,就可以让每个任务有条不紊的、持续的进行下去了。
整个过程,被称之为事件循环

9.js的事件循环理解

(1)事件循环又叫做消息循环,是浏览器渲染主线程的工作方式。
(2)在Chrome的源码中,它开启一个不会结束的for循环,每次循环从消息队列中取出第一个任务执行,而其他线程只需要在合适的时候将任务加入到队列末尾即可。
过去把消息队列简单分为宏队列和微队列,这种说法目前已无法满足复杂的浏览器环境,取而代之的是一种更加灵活多变的处理方式。
(3)根据W3C官方的解释,每个任务有不同的类型,同类型的任务必须在同一个队列,不同的任务可以属于不同的队列。不同任务队列有不同的优先级,在一次事件循环中,由浏览器自行决定取哪一个队列的任务。但浏览器必须有一个微队列,微队列的任务一定具有最高的优先级,必须优先调度执行

10.为什么定时器嵌套超过五层以后最小延迟时间被设为4ms

对定时器的执行频率进行了限制,以便优化性能和防止性能问题

11.JS中的计时器能做到精确计时吗?

不行
1.计算机硬件没有原子钟,无法做到精确计时
2.操作系统的计时函数本身就有少量偏差,由于JS的计时器最终调用的是操作系统的函数,也就携带了这些偏差
3.按照W3C的标准,浏览器实现计时器时,如果嵌套层级超过5层,则会带有4毫秒的最少时间,这样在计时时间少于4毫秒时又带来了偏差
4.受事件循环的影响,计时器的回调函数只能在主线程空闲时运行,因此又带来了偏差

  • 12
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值