JavaScript 运行机制 线程进程

113 阅读5分钟

进程

  • CPU 分配资源的最小单位

  • 进行中的程序及其所使用的内存和资源

  • CPU 通过时间片的轮转来实现多进程

浏览器

  • Chrome:每打开一个Tab页就会产生一个进程

浏览器包含哪些进程

Browser进程

  1. 浏览器的主进程(负责协调、主控),该进程只有一个

  2. 界面显示,用户交互

  3. 将渲染(Renderer)进程得到的内存中的Bitmap(位图),绘制到用户界面上

  4. 网络资源的管理,下载等

第三方插件进程

  1. 每种类型的插件对应一个进程,当使用该插件时才创建

GPU进程

  1. 该进程也只有一个,3D渲染

渲染进程

  1. 浏览器内核(Renderer进程,内部是多线程)

  2. 每个Tab页面都有一个渲染进程,互不影响

  3. 主要作用为页面渲染,脚本执行,事件处理等

为什么浏览器要多进程

  • 如果浏览器是单进程,那么某个Tab页崩溃会影响了整个浏览器

    • 同理如果插件崩溃了也会影响整个浏览器。
  • 浏览器进程有很多,每个进程又有很多线程,都会占用内存

渲染进程

GUI渲染线程

  1. 负责渲染浏览器界面,解析HTML,CSS,构建DOM树,RenderObject树,布局,绘制

    1. 解析html代码(HTML代码本质是字符串)转化为浏览器认识的节点,生成DOM树(DOM Tree)

    2. 解析css,生成CSSOM(CSS规则树)

    3. 把DOM Tree 和CSSOM结合,生成Rendering Tree(渲染树)

  2. 修改颜色或者背景色,页面就会重绘(Repaint)

  3. 修改元素的尺寸,页面就会回流(Reflow)

  4. 当页面需要Repaing和Reflow时,GUI线程执行,绘制页面

  5. 回流(Reflow)比重绘(Repaint)的成本要高,要尽量避免Reflow和Repaint

  6. GUI渲染线程与JS引擎线程是互斥的

    1. 当JS引擎执行时GUI线程会被挂起(相当于被冻结了)

    2. GUI更新会被保存在一个队列中等到JS引擎空闲时立即被执行

JS引擎线程

  1. JS引擎线程就是JS内核,负责处理Javascript脚本程序(例如V8引擎)

  2. 负责解析Javascript脚本,运行代码

  3. JS引擎一直等待着任务队列中任务的到来,再加以处理

    1. 浏览器同时只能有一个JS引擎线程在运行JS程序,所以js是单线程运行的

    2. 一个Tab页(renderer进程)中无论什么时候都只有一个JS线程在运行JS程序

  4. GUI渲染线程与JS引擎线程是互斥的,js引擎线程会阻塞GUI渲染线程

    1. JS执行时间过长,造成页面的渲染不连贯,导致页面渲染加载阻塞(就是加载慢)

    2. 浏览器渲染的时候遇到

      • js执行时间太长就会造成页面卡顿的情况

      • defer:JS 延迟执行,直到 DOM 渲染完

      • async:不会让脚本阻塞文档

事件触发线程

  • onClick methods handle task queue
  1. 属于浏览器而不是JS引擎,用来控制事件循环,并且管理着一个事件队列(task queue)

  2. 事件绑定和异步操作(如setTimeOut,也可来自浏览器内核的其他线程,如鼠标点击、AJAX异步请求等),会走事件触发线程将对应的事件添加到对应的线程中(比如定时器操作,便把定时器事件添加到定时器线程),等异步事件有了结果,将其回调操作添加到事件队列,等待js引擎线程空闲时来处理

  3. 当对应的事件符合触发条件被触发时,该线程会把事件添加到待处理队列的队尾,等待JS引擎的处理

  4. JS是单线程,所以这些待处理队列中的事件都得排队等待JS引擎处理

定时触发器线程

  1. setInterval与setTimeout所在线程

  2. 浏览器定时计数器并不是由JavaScript引擎计数的(因为JavaScript引擎是单线程的,处于阻塞线程状态就会影响记计时的准确)

  3. 通过单独线程来计时并触发定时(计时完毕后,添加到事件触发线程的事件队列中,等待JS引擎空闲后执行),这个线程就是定时触发器线程,也叫定时器线程

  4. W3C在HTML标准中规定,规定要求setTimeout中低于4ms的时间间隔算为4ms

异步http请求线程

  1. 在XMLHttpRequest在连接后是通过浏览器新开一个线程请求

  2. 当执行到一个http异步请求时,就把异步请求事件添加到异步请求线程,等收到响应(准确来说应该是http状态变化),再把回调函数添加到事件队列,等待js引擎线程来执行

线程

  • CPU 调度的最小单位

  • 进程里面可以包含多个进程

    • 单线程操作
  • 同一个进程中的线程可以共享进程中的资源

  • 定时器

JS 为什么是单线程

  • 如果是双线程,dom 同时操作 body 添加和删除时会产生混乱