浏览器渲染原理
回流reflow
- 第一次确定节点的大小和位置,称之为布局layout
- 之后对节点的大小,位置修改重新计算称之为回流
如何引起回流
- DOM结构发生改变(添加新的节点或者移除节点)
- 改变了布局(修改了width,height,padding,font-size等值)
- 窗口resize(修改窗口的尺寸)
- 调用getComputedStyle方法获取尺寸,位置信息
回流一定会引起重绘,所以回流是非常消耗性能的事情
重绘repaint
- 第一次渲染内容称之为绘制(paint)
- 之后重新渲染称之为重绘
如何引起重绘
- 背景色,文字颜色,边框颜色,样式
在开发中尽量避免发生回流
修改样式时尽量一次性修改
- 通过cssText,比如通过添加class修改
尽量避免频繁的操作DOM
- 可以在一个DocumentFragment或者父元素中将要操作的DOM操作完成,再一次性的操作
尽量避免通过getComputedStyle获取尺寸,位置信息
对某些元素使用position的absolute或fixed
- 并不是不会引起回流,而是开销相对较小,不会对其他元素造成影响
合成composite
多个图层好处,一个图层进行了修改并不会影响其他图层导致其他图层需要重新渲染
- 绘制的过程,可以将布局后的元素绘制到多个合成图层中
- 浏览器的一种优化手段
- 默认情况下,标准流的内容都是被绘制在同一个图层Layer中
- 一些特殊的属性,会创建一个新的合成层,并且新的图层可以利用GPU来加速绘制
- 因为每个合成层都是单独渲染的
常见的形成新的合成层的一些属性
- 3D transforms
- video, canavas, iframe
- opacity动画转换
- position:fixed
- will-change:提前告诉浏览器元素可能发生哪些变化
- animation或transition设置了opacity,transform
分层确实可以提高性能,但是以内存管理为代价,因此不应作为web性能优化策略的一部分过度使用.
script元素和页面解析的关系
- 浏览器在解析HTML的过程总遇到了script元素是不能继续构建DOM树
- 它会停止继续构建,首先下载js代码,并且执行js的脚本
- 只有等到js脚本执行结束后,才会继续解析HTML,构建DOM树
这么做的原因,因为JS涉及大量DOM操作,如果等到DOM树构建完成并且渲染好了再执行JS会造成严重的回流和重绘,影响页面性能.
但这也会带来新问题,现代网页开发中,脚步往往比HTML页面更重,处理时间需要更长;所有会造成页面的解析阻塞,在脚步下载执行完成之前,用户在界面上什么都看不到
为解决这个问题script提供了两个属性defer,async
(需要注意,为了达到更好的用户体验,呈现引擎会力求尽快将内容显示在屏幕上,它不必等到整个HTML文档解析完毕之后,就会开始构建呈现树和设置布局)
defer
defer属性告诉浏览器不要等待JS下载,而继续解析HTML,构建DOM Tree
- 脚本会由浏览器来进行下载,但是不会阻塞DOM Tree的构建过程
- 脚本提前下载好了,它会等待DOM Tree构建完成,在DOMContentLoaded事件之前先执行defer中的代码
DOMContentLoaded总是会等待defer中的代码先执行完成
推荐将defer的脚本放入head中.
async
async是让一个脚本完全独立的:
- 浏览器不会因async脚步而阻塞
- async脚步不能保证顺序,它是独立下载,独立运行,不会等待其他脚本
- async不会能保证在DOMContentLoaded之前或之后执行
defer通常用于需要再文档解析后操作DOM的js代码,并且对多个script文件有顺序要求