浏览器机制
浏览器渲染分为几步
- javascript javascript实现动画效果,DOM元素操作
- style 确认每一个DOM元素是用什么css规则
- layout 计算每一个DOM元素在屏幕上的显示的大小和位置。由于元素布局是相对的,所以,每次任意一个元素发生变化,都会联动其他元素发生变化,这个过程称为reflow
- paint 在多个层上绘制DOM元素的文字,颜色,图像,边框和阴影等
- composite : (渲染层合并) 按照合理的顺序合并图层显示到屏幕上
javascript 执行效率优化
- 避免使用setTimeout 和 setInterval 的使用,尽量使用requestAnimationFrame()
setTimeout 和 setInterval 无法保证callback 的执行时机,有可能在帧结束才执行,从而导致掉帧
window.requestAnimationFrame(): 该方法是告诉浏览器您希望请求执行动画并请求浏览器调用指定函数在下一次重绘之前更新动画,使用一个回调函数作为参数,这个回调函数会在浏览器重绘之前执行
script标签的工作原理
- 浏览器一边下载html网页,一边开始解析
- 解析过程中,发现script标签
- 暂停渲染,网页渲染的控制权交给javascript引擎
- 如果script标签引用了外部文件,就下载文件,否则就直接执行
- 执行完毕,控制权交还给渲染引擎,恢复下面html网页的解析
在浏览器遇到多个script标签引用外部文件,浏览器会并行下载这些外部文件,下载完成后会按照顺序来执行这些外部文件,即使后面的文件比前面的文件先下载完成
defer 属性
defer属性是用来解决脚本文件下载阻塞网页渲染的问题,script中加了这个属性之后,就会等到网页DOM都加载完成之后,才会执行js
defer的运行过程如下
- 浏览器开始执行html网页
- 解析过程中,遇到带有defer属性的script标签
- 浏览器继续往下解析浏览器网页,同时并行下载script标签中的外部文件
- 浏览器完成解析html网页,此时再执行下载的脚本
对于内置不是外部文件的script标签,以及动态加载的script标签,defer属性不起作用。另外,使用defer加载外部脚本时不应该使用document.write
async 属性
async 是使用另外一个线程下载文件,下载时不会阻塞网页渲染
async的运行过程如下
- 浏览器开始执行html网页
- 解析过程中,遇到带有async属性的script标签
- 浏览器继续解析网页,并且同时下载script脚本
- script下载完成后,浏览器停止解析网页,开始执行下载好的script代码
- 脚本执行完成,浏览器恢复对网页的解析
注意:async属性也可以保证脚本下载的同时,浏览器继续渲染页面,但是用这个属性没有办法保证脚本的执行顺序。哪个先下载完成,哪个就执行。
defer和async属性到底选哪个?
一般来说,如果两个脚本之间没有依赖关系,就选用async属性,否则就选用defer属性。如果同时使用defer和async,defer就不起作用,浏览器行为按照async属性决定。
脚本的动态加载
我们可以动态生成script标签,然后加入页面,从而实现脚本的动态加载。这样方法的好处是,动态生成的script标签不会阻塞网页的解析渲染,也不会造成浏览器的假死。但是有一个问题就是,不能够保证脚本的执行顺序。哪个脚本下载完成先,哪个脚本就先执行。
要想解决这个问题,可以在动态添加script标签的时候,将async的属性设置为false.
浏览器的组成
浏览器的核心分两部分:渲染引擎和javascirpt引擎(浏览器解析器)
渲染引擎
渲染引擎的主要作用就是将网页代码渲染为用户视觉可以感知的平面文档
渲染引擎处理网页分四个部分:
- 解析代码:HTML代码解析为DOM树,css代码解析为cssDOM样式树
- 对象合并:将DOM树和cssOM合并为一个渲染树(render tree)
- 布局: 计算渲染渲染树的大小和坐标进行布局(layout)
- 绘制: 将渲染树渲染到屏幕上面去
渲染性能优化
- 读取DOM或者写入DOM,尽量要写在一起
- 缓存DOM信息
- 改变样式的时候,不要一项一项的改,而是使用css class一次性改变样式
- 使用documentFragment操作DOM
- 动画是使用display:absolute或者是fixed定位,这样可以减少对其他dom元素的影响
- 使用window.requestAnimationFrame()操作动画,因为他可以把代码推迟到下一次重流是执行,而不是立即要求页面重流
- 使用虚拟DOM库
下面是使用window.requestAnimationFrame的对比例子
// 重绘代价高
function doubleHeight(element) {
var current = element.clientHeight;
element.style.height = (current * 2) + 'px';
all_element.forEach(doubleHeight)
}
// 重绘代价低
function doubleHeight(element) {
var current = element.clientHeight;
window.requestAnimationFrame(function() {
element.style.height = (current * 2) + 'px';
})
all_element.forEach(doubleHeight)
}
javascript引擎
javascript引擎的主要作用是,读取网页中的javacript代码,对其处理后运行