内核
JS引擎
渲染引擎
HTML 解释器、CSS 解释器、图层布局计算、网络、存储、图形、音视频、图片解码器等等零部件
渲染模块
HTML 解释器:将 HTML 文档经过词法分析输出 DOM 树<br>
CSS 解释器:解析 CSS 文档, 生成样式规则
图层布局计算模块:布局计算每个对象的精确位置和大小
视图绘制模块:进行具体节点的图像绘制,将像素渲染到屏幕上
JavaScript 引擎:编译执行 Javascript 代码
渲染过程
解析 HTML ——> 计算样式 ——> 计算图层布局 ——> 绘制图层 ——> 整合图层,得到页面
相关“树”
DOM 树
解析 HTML 以创建的是 DOM 树
CSSOM 树
解析 CSS创建的是 CSSOM 树(与解析DOM树并行)
渲染树
CSSOM 与 DOM 结合,得到渲染树 Render tree
布局渲染树
计算每个节点应该出现在屏幕上的精确坐标,得到布局渲染树
绘制渲染树
遍历渲染树,每个节点将使用 UI 后端层来绘制,得到绘制渲染树
基于渲染的优化
CSS 优化
避免使用通配符,只对需要用到的元素进行选择
关注可以通过继承实现的属性,避免重复定义
少用标签选择器
不要画蛇添足,.myList#title
减少嵌套
减少阻塞
CSS 阻塞
CSS 是阻塞渲染的资源,需要将它尽早(CSS放置页面首部)、尽快(CDN)地下载到客户端
JS 阻塞
JS 对 DOM 和 CSSDOM 进行修改,会阻塞 DOM
本质
JS 引擎抢走了渲染引擎的控制权,JS 引擎运行完毕之后又把控制权还给渲染引擎,继续渲染
加载方式
defer 模式
异步加载,不会阻塞,执行推迟(整个文档解析完成后)
DOM 优化
减少 DOM 操作:JS 层面的事情,JS 自己去处理,处理好了,再来操作 DOM
异步更新
是什么
更新数据时不会立即执行,会等一个时机批量触发,可以帮助我们避免过度渲染
优越性
只看结果,不需要为过程买单,举例:更改同一个dom内容三次,异步更新只会更新最后一次
Event Loop
分类
macro(宏任务)队列
比如:setTimeout、setInterval、 setImmediate、script(整体代码)、 I/O 操作、UI 渲染等
micro(微任务)队列
比如: process.nextTick、Promise、MutationObserver 等
回流和重绘
重绘
是什么
DOM 的修改只是导致了样式的变化,并未改变几何属性,浏览器只需要绘制新的样式即可<br>
回流(重排)
是什么
DOM 的修改引发了 DOM 几何尺寸的变化,浏览器需要重新计算元素的几何属性<br>
触发情况
改变 DOM 元素的几何属性
改变 DOM 树的结构
获取一些特定属性的值(比如offsetTop、offsetLeft、 offsetWidth、offsetHeight、scrollTop......clientTop...... )<br>这些值需要通过即时计算得到。因此浏览器为了获取这些值,也会进行回流<br>
如何规避
将改变缓存起来,避免频繁触发回流
避免逐条改变样式,使用类名去合并样式
让 DOM 消失,执行操作之后,再展示(适用于对dom执行很多操作的情况下)
机智的浏览器
浏览器将DOM操作缓存一个 flush 队列,存放回流与重绘任务
等到任务多 or 到了一定的时间间隔 or 特殊情况下,执行出队
这是机智的Chrome,并不代表其他浏览器智商也一样,所以还是尽量手动规避