浏览器渲染原理以及性能优化
浏览器渲染原理
进程与线程
- 当我们打开一个网页的时候,就创建了一个进程
- 一个进程可以同时干多件事,这就是多线程
Request请求阶段
- DNS解析
- TCP协议的三次握手和四次挥手
拓展:HTTPS与HTTO的区别(HTTP2)
Response响应阶段
- 获得 HTTP状态码,304缓存(性能优化),HTTP报文
- 开辟栈内存
当浏览器拿到代码后,浏览器在内存条中开辟出一块栈内存,用来给代码的执行提供环境,同时分配一个主线程去一行行的解析和执行代码- 这就解释了为什么JS是单线程的,因为浏览器只会分配一个线程去解析与执行代码
- 一行行代码进栈执行,执行完之后出栈
- 如拿到网页后,我们首先解析到 ,会判断到这是一个html页面,然后这一行代码出栈,解析下一行代码。
- 当遇到
link/script/img
等,会开辟全新的线程,去加载资源文件,从而形成一个任务队列这里面有个 微任务和宏任务 的概念 - CSS处理完成生成 CSSOM 也是一个树
- 主任务队列(主线程)自上而下走完之后,只生成了DOM树,这个时候会去查看任务队列中什么完成了,完成之后就处理,处理完之后再去队列里面看直到完成为止。(事件循环)
- DOM树跟CSSOM结合后得到 Render Tree
浏览器渲染网页注意事项
-
DOM的构建过程是一个深度遍历的过程,即当前节点的所有子节点都构建好以后才会去构建当前节点的下一个兄弟节点
-
渲染树和DOM不同,因为像DOM树中的display:none元素不会出现在渲染树中,但visibility: hidden会出现在渲染树中
-
DOM解析和CSS解析是同时进行,互不影响
-
渲染树的生成并不是等到DOM树和CSS规则树解析完成才开始合并,而是边解析、边合并渲染
浏览器渲染网页阻塞顺序
-
构建DOM树时,如遇到JS元素时,会阻塞DOM树和CSS规则树的构建,优先执行JS文件
-
构建DOM树时,如遇到CSS元素时,会开启异步请求线程,该线程会先下载CSS文件,再构建CSS规则树,该线程会阻塞JavaScript引擎线程,但不会阻塞DOM树的构建
-
CSS解析和JS解析互斥,也就是说JS解析时会阻塞CSS解析而CSS解析时也会阻塞JS解析
-
JS解析时,如果JS还操作了CSS,而这个CSS还没有下载或构建解析,则会延迟执行JS,直到完成CSS下载构建解析,再会继续执行JS
DOM的重绘和回流 Repaint & Reflow
- DOM的重绘 Repaint
元素样式的改变(但宽高,大小,位置并不变)
如 outline,visibility,color,background-color 等 - DOM的回流 Reflow
元素大小或者位置发生了改变(当页面布局和几何信息发生改变的时候),触发了重新布局,导致渲染树重新计算布局和渲染
注意: 回流一定会触发重绘,而重绘不一定会回流
原理图
- 解析HTML,声称DOM树,解析CSS,生成CSSOM树
- 将DOM树和CSSOM数结合,生成渲染树
- Layout(回流):根据生成的渲染树,计算它们在设备视口(viewport)内的确切位置和大小,之歌计算的阶段就是回流
- Painting(重绘):根据渲染树以及回流得到的几何信息,得到节点的绝对像素
- Display:将像素发送到GPU,展示在页面上
性能优化
- 减少 HTTP 的请求次数和大小
- 资源合并压缩 (webpack)
- 图片懒加载
- 音视频走流文件 (m3u8)
- 避免DOM的回流
- 放弃传统操作dom的时代,基于vue/react开始数据影响视图模式(虚拟dom)
mvvm / mvc / virtual dom / dom diff … - 分离读写操作(现代的浏览器都有渲染队列的机制)
- 样式集中改变
- 缓存处理
let a = box.clientWidth; let b = box.clientHeight; box.style.width = a + 10 + 'px'; box.style.height = b + 10 + 'px';
- 代码批量处理
// 文档碎片 let frg = document.createDocumentFragment(); for (let i = 0; i < 5; i++) { let newLi = document.createElement('li'); newLi.innerHTML = i; // 创建的li放到文档碎片中 frg.appendChild(newLi); } // 一次性把所有的内容放到容器中,引发一次回流 box.appendChild(frg); frg=null; // 字符串拼接 let str = ``; for (let i = 0; i < 5; i++) { str+= `<li>${i}</li>`; } box.innerHTML=str;
- 动画效果应用到position属性为absolute或fixed的元素上(脱离文档流)
- CSS3硬件加速(GPU加速)
- 直接不要回流重绘, 使用 transform \ opacity \ filters … 这些属性会触发硬件加速,不会引发回流和重绘…
- 牺牲平滑度换速度
- 避免table布局和使用css的javascript表达式
- 放弃传统操作dom的时代,基于vue/react开始数据影响视图模式(虚拟dom)