既然要说事件循环,就需要从浏览器线程开始说起

浏览器进程

  • 在浏览器中每开启一个tab页,就开启了对应tab页进程,每个页面互不影响
  • 一个页面相当于一个进程,一个进程有多个线程互相配合

浏览器tab页中的进程主要由以下线程构成

浏览器存在很多线程(事件触发线程互相操作)其中主线程是JS引擎线程
GUI渲染线程(常驻线程)

  1. 渲染浏览器界面,解析html,css,构建dom树,布局和绘制
  2. 该线程与JS线程互斥,当js引擎执行时,该引擎会被挂起,会保存在一个队列中等到JS引擎空闲时立即执行

JS引擎线程(常驻线程)(JS内核)

  1. 负责处理JavaScript脚本程序(例如V8引擎),解析JavaScript脚本,运行代码
  2. 一个页面中只有一个JS线程在运行JS程序
  3. 如果JS引擎运行时间过长,会造成阻塞页面加载,影响GUI渲染线程页面加载
  4. 当JS引擎修改DOM的时候,如果同时运行GUI引擎,会造成页面数据不一致
  5. 因此GUI更新会放到任务队列中,等JS引擎空闲时立即执行

浏览器事件线程(常驻线程)

  1. 该事件归属于浏览器,用来控制事件循环
  2. JS引擎遇到事件时(不是首先同步处理的事件),DomEvent事件等,会将这些任务添加到该事件线程中
  3. 当事件符合触发条件被触发时(如点击,移动等操作),该线程会把事件添加到任务队列末尾,等待JS引擎的处理
  4. 由于JS时单线程,所以任务队列需要等待JS引擎依次处理
  5. 定时器触发线程(setTimeout和setInterval)
  6. 定时器不是由JS引擎计数的,因为JS是单线程,如果处于阻塞状态就会影响计时的准确
  7. 所以当计时完毕后,会添加到任务队列末尾,等待JS引擎执行
  8. 注意!!!
    1. 如果JS引擎处理其他任务超过定时器时间
    2. 如定时器5000ms,比如循环事件用了6000ms,就算定时器线程在5000ms的时候把执行函数放入到任务事件队列末尾,也必须等循环结束后才能调用,这就造成实际是6000ms的时候才触发定时器

异步http请求线程

  1. 当XMLHttpRequest连接后,浏览器会新开一个线程请求
  2. 当检测到状态变更时(onreadystateChange = function () {}
  3. 如果设有回调函数,该异步线程就产生状态变更事件,将回调函数放入事件队列末尾,再由JS引擎执行

https://www.youtube.com/watch?v=8aGhZQkoFbQ
https://vimeo.com/96425312
image.png