浏览器中的事件循环

308 阅读3分钟

事件循环 浏览器本身是一个复杂的系统,它要做的事情非常多,例如: 执行js代码,请求图片资源,解析css,渲染页面,响应鼠标的点击等等。在实现层面,浏览器内部会用不同的功能模块去完成不同的事情。这些不同的模块就体现为进程。

image.png

image.png

image.png 进一步把进程进行划分:

  1. 主进程。用来协调控制其他子进程。
  2. GPU进程。用于3D绘制等。
  3. 渲染进程。就是我们说的浏览器内核,负责具体页面的渲染,脚本执行,事件处理等。每个tab页背后就有一个渲染进程。

进程这个单位还是比较大,它进一步拆分多个线程。可以理解为一个页面上的事还是比较多,要多找些小弟来完成。具体来说,一个渲染进程包括:

  1. 主线程。统一调度
  2. GUI渲染线程。负责渲染页面,布局和绘制。与JS引擎互斥。
  3. JS引擎线程。负责处理解析和执行javascript脚本程序。
  4. 事件触发线程。用来控制事件循环(鼠标点击、setTimeout、ajax等)。当事件满足触发条件时,将事件放入到JS引擎所在的执行队列中。
  5. setInterval与setTimeout所在的线程。定时任务并不是由JS引擎计时的,是由定时触发线程来计时的。计时完毕后,通知事件触发线程
  6. 异步http请求线程。浏览器有一个单独的线程用于处理AJAX请求,当请求完成时,若有回调函数,通知事件触发线程。
  7. io线程。用来接收其他进程的消息。

每个渲染进程都有一个主线程,并且主线程非常繁忙,既要处理 DOM,又要计算样式,还要处理布局,同时还需要处理 JavaScript 任务以及各种输入事件。要让这么多不同类型的任务在主线程中有条不紊地执行,这就需要一个系统来统筹调度这些任务,这个统筹调度系统就是消息队列和事件循环。

任务有很多,人只有一个,且任意时刻只能做一件事(不是一边走路一边听课这种事哈),那怎么办,就是排队呗

eventLoop

image.png

  1. 主线程上要做很多事情,例如:js代码执行,页面布局计算,渲染等
  2. 主线程同一时刻只能做一件事,事情多了就要排队。所以主线程维护了任务队列。
  3. 某个事件发生时,事件触发线程 就把对应的任务添加到主线程的任务队列中。
  4. 主线程上的任务完成之后,就会从任务队列中取出任务来执行。

任务是以事件及其回调的方式存在的。当事件(用户的点击,图片的成功加载)发生时,将其回调添加到任务队列;主线程上的任务完成之后,就会从任务队列中取出任务来执行,此过程不断重复从而形成一个循环,称为eventLoop。

要点回顾:

  • 事件循环不是js的语言层面的内容,是js的宿主环境(浏览器,nodeJS)的讨论内容。在js代码中讨论事件循环是没有意义的。
  • 在更广的领域。事件循环是一个典型的生产者/消费者模型。异步I/O,网络请求是事件的生产者,源源不断提供事件,这些事件被传递到对应的观察者那里,事件循环则从观察者那里取出事件并处理。
  • 在windows下,这个循环基于IOCP创建,而在*nix下基于多线程创建。