关于浏览器渲染你想知道的都在这里

在讲浏览器渲染之前,我们先来理解js引擎执行过程。

js引擎的执行过程,分为三个阶段

1、语法分析

2、预编译阶段

3、执行阶段

一、语法分析:

浏览器先按照js的顺序加载<script>标签分隔的代码块,js代码块加载完毕之后,会首先进入到语法分析阶段,该阶段的主要作用:

分析该js脚本代码块的语法是否正确,如果出现不正确会向外抛出一个语法错误(syntaxError),停止改js代码的执行,然后继续查找并加载下一个代码块;如果语法正确,则进入到预编译阶段。

二、预编译阶段

通过语法分析阶段后,进入预编译阶段,则创建变量对象(创建arguments对象(函数运行环境下),函数声明提前解析,变量声明提升),确定作用域链以及this指向。

js的运行环境主要有三种:

1、全局环境(js代码加载完毕后,进入到预编译也就是进入到全局环境)

2、函数环境(函数调用的时候,进入到该函数环境,不同的函数,函数环境不同)

3、eval环境(不建议使用,存在安全、性能问题)

每进入到一个不同的运行环境都会创建 一个相应的执行上下文(execution context),那么在一段js程序中一般都会创建多个执行上下文,js引擎会以栈的数据结构对这些执行进行处理,形成函数调用栈(call stack),栈底永远是全局执行上下文(global execution context),栈顶则永远时当前的执行上下文。

三、执行阶段(重点理解)

先思考以下两个问题:

1、js是单线程的,为了避免代码解析阻塞使用了异步执行,那么它的异步执行机制是怎么样的?

答:通过事件循环(Event Loop),理解了事件循环的原理就理解了js的异步执行机制。

2、js是单线程的,那么是否代表参与js执行过程的线程就只有一个?

答:不是的,会有四个线程参与该过程,但是永远只有JS引擎线程在执行JS脚本程序,其他的三个线程只协助,不参与代码解析与执行。参与js执行过程的线程分别是:

(1)JS引擎线程: 也称为JS内核,负责解析执行Javascript脚本程序的主线程(例如V8引擎)。

(2)事件触发线程: 归属于浏览器内核进程,不受JS引擎线程控制。主要用于控制事件(例如鼠标,键盘等事件),当该事件被触发时候,事件触发线程就会把该事件的处理函数推进事件队列,等待JS引擎线程执行。

(3)定时器触发线程:主要控制计时器setInterval和延时器setTimeout,用于定时器的计时,计时完毕,满足定时器的触发条件,则将定时器的处理函数推进事件队列中,等待JS引擎线程执行。

注:W3C在HTML标准中规定setTimeout低于4ms的时间间隔算为4ms。

(4)HTTP异步请求线程:通过XMLHttpRequest连接后,通过浏览器新开的一个线程,监控readyState状态变更时,如果设置了该状态的回调函数,则将该状态的处理函数推进事件队列中,等待JS引擎线程执行。

注:浏览器对同一域名请求的并发连接数是有限制的,Chrome和Firefox限制数为6个,ie8则为10个。

  • 什么是事件循环

事件循环可以理解成由三部分组成,分别是:

1、主线程执行栈

2、异步任务等待触发

3、任务队列(任务队列(task queue)就是以队列的数据结构对事件任务进行管理,特点是先进先出,后进后出。)

image

在JS引擎主线程执行过程中:

1、首先执行宏任务的同步任务,在主线程上形成一个执行栈,可理解为函数调用栈。

2、当执行栈中的函数调用到一些异步执行的API(例如异步Ajax,DOM事件,setTimeout等API),则会开启对应的线程(Http异步请求线程,事件触发线程和定时器触发线程)进行监控和控制。

3、当异步任务的事件满足触发条件时,对应的线程则会把该事件的处理函数推进任务队列(task queue)中,等待主线程读取执行。

4、当JS引擎主线程上的任务执行完毕,则会读取任务队列中的事件,将任务队列中的事件任务推进主线程中,按任务队列顺序执行

5、当JS引擎主线程上的任务执行完毕后,则会再次读取任务队列中的事件任务,如此循环,这就是事件循环(Event Loop)的过程。

四、浏览器渲染进程

浏览器渲染进程,从接收下载文件后再到呈现整个页面的过程,由浏览器渲染进程负责,主要流程如下:

  1. 解析HTML文件和CSS文件,加载图片等资源文件,渲染成用户看到的页面
  2. 执行解析js文件脚本代码
    在该过程中浏览器渲染进程会开启多个线程协作完成,主要的线程以及作用如下:
    1. GUI渲染线程
      1. 负责解析HTML文件构建DOM树,解析CSS,结合DOM树渲染成RenderObject树,然后布局和绘制页面
      2. 当RenderObject树需要更新样式属性时,即发生重绘(Repaint);当RenderObject树中的元素规则尺寸,布局或显示隐藏等发生变化,即发生回流(reflow)。
    2. JS引擎线程
    3. 时间出发线程
    4. 定时器触发线程
    5. 异步Http请求线程

注:GUI渲染线程与JS引擎线程是相互排斥的,因为JS引擎线程在执行的过程中可能会发生重绘和回流,所以GUI渲染线程执行时候,JS引擎线程会被挂起,等待GUI渲染线程执行完毕之后,JS引擎线程执行时候同理。

3.GUI渲染线程


image

GUI渲染线程执行的详细过程:

  1. 解析HTML文件,构建DOM树,同时浏览器主进程负责下载CSS文件
  2. CSS文件下载完成,解析CSS文件成树形的数据结构,然后结合DOM树合并成RenderObject树
  3. 布局RenderObject树,负责RenderObject树中的元素的尺寸,位置等计算
  4. 绘制RenderObject树,绘制页面的像素信息
  5. 浏览器主进程将默认的图层和复合图层交给GPU进程,GPU进程再将各个图层合成(conposite),最后显示出页面

总结

主要是介绍浏览器的渲染过程,但是没有分析js脚本文件解析过程。

(一)浏览器渲染进程包含1、解析HTML文件和CSS文件,加载图片等资源文件,渲染成用户看到的页面;2、执行解析js文件脚本代码。

(二)整个过程浏览器会开启多个线程协作完成,包括:GUI渲染线程,JS引擎线程,事件触发线程,定时器触发线程,异步HTTP请求线程。

(三)其中GUI渲染线程和JS引擎线程是相互排斥的,因为JS引擎线程在执行的时候有可能会发生重绘和回流。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容