事件循环机制

31 阅读4分钟

首先大家需要了解一下浏览器里面的一些简单知识

浏览器的进程模型

进程

概念:一个正在运行的程序的实例(简单理解:一个程序运行需要专属的内存空间,这个内存空间可以被简单理解为进程),是系统资源分配的最小单位。

特点

  1. 独立的内存空间;
  2. 进程之间相互隔离,相互独立(通信要双方同意);
  3. 启动开销大(独立资源);

例子: 打开微信,微信会是一个进程;

线程

概念进程中的执行单元,CPU调度和执行的最小单元。

主线程:一个进程至少有一个线程,进程开启后自动创建的一个线程。

如果程序需要同时执行多块代码,就会启动更多的线程来执行代码。

特点

  1. 共享进程的内存空间;

  2. 线程之间切换开销小,适合并发处理;

  3. 一个进程包含多个线程;

例子:微信的主界面是一个线程,接收消息是另一个线程,播放语音是另一个线程。

对比

屏幕截图 2025-07-28 220440.png

浏览器有哪些进程和线程?

浏览器是一个多进程多线程的应用程序,为了避免相互影响,减少连环崩溃的几率。(在浏览器的任务管理器中查看当前的所有进程)

最主要的进程

  1. 浏览器进程:主要负责界面显示、用户交互、子进程管理等。

  2. 网络进程:负责加载网络资源。

  3. 渲染进程:渲染进程启动后,会开启一个渲染主线程(负责执行 HTML、CSS、JS 代码)。默认情况下,浏览器会为每个标签页开启一个新的渲染进程,以保证不同的标签页之间不相互影响。

渲染主线程是如何工作的?

工作核心:排队执行各项任务,渲染主线程工作的整个过程就叫做事件循环

工作流程(事件循环):

  1. 最开始时,渲染主线程进入一个无限循环。

  2. 每一次循环会检查消息队列里面是否有任务,有就按照队列的形式(先进先出)循环取出任务执行,如果没有就进入休眠状态。

  3. 其他所有的线程都可以随时向消息队列添加新任务(进入队列末尾)。如果在添加新任务时,主线程休眠,就唤醒它继续循环执行任务。

image.png 现在出现一个问题,渲染主线程只有一个,渲染主线程是使用JS去执行任务的,JS是一个单线程语言,遇到无法立刻处理的任务,就需要等待,主线程处于阻塞状态,导致浏览器卡死,如何解决?

image-20220810104344296

异步

使用异步来解决之前的问题。

具体流程:当某些任务发生时,比如计时器、网络、事件监听,主线程将任务交给其他线程去处理,自身立即结束任务的执行,转而执行后续代码。当其他线程完成时,将事先传递的回调函数包装成任务,加入到消息队列的末尾排队,等待主线程调度执行。

image.png

消息队列的优先级

之前消息队列分为宏队列(如setTimeout、setInterval、DOM 事件等)和微队列(如Promise.then、MutationObserver等),队列执行顺序:主线程>微队列>宏队列

现在W3C官方的解释:

  • 每个任务有不同的类型,同类型的任务必须在同一个队列,不同的任务可以属于不同的队列。

  • 不同任务队列有不同的优先级,在一次事件循环中,由浏览器自行决定取哪一个队列的任务。

  • 但浏览器必须有一个微队列,微队列的任务一定具有最高的优先级,必须优先调度执行。

目前Chrome至少包含了:延时队列(优先级中);交互队列(优先级高);微队列(优先级最高)

JS会阻塞渲染的原因?

因为 js 的执行和页面的渲染都是在渲染主线程进行的,当在执行 js 的时候,可能会有一些页面的渲染任务还在消息队列排队,从而造成阻塞渲染

现在出现一个问题,渲染主线程只有一个,渲染主线程是使用JS去执行任务的,JS是一个单线程语言,遇到无法立刻处理的任务,就需要等待,主线程处于阻塞状态,导致浏览器卡死,如何解决?