浏览器渲染流程,回流重绘,defer与async

202 阅读4分钟

1.浏览器的内核

  • Teident(三叉戟):IE,360浏览器,搜狗浏览器,百度浏览器,UC浏览器

  • Gecko(壁虎):Mozilla Firedfox

  • Presto(急板乐曲)->Blink(眨眼):Opera

  • Webkit:Safari,360极速浏览器,搜狗浏览器,移动端浏览器(Android,ios)

  • Webkit->Blink:Google Chrome,Edge

    浏览器内核指的是浏览器的排版引擎,也称为浏览器引擎,页面渲染引擎或样板引擎

2.渲染页面的详细流程

  1. 解析HTML,会构建DOM Tree(默认情况)

  2. 生成css规则

    • 解析HTML中遇到css的link元素,浏览器会下载对应的css文件(下载css文件不会印象DOM解析)。
    • 下载完css文件后,浏览器会对css文件进行解析,解析出对应的规则树,称之为CSSOM(CSS Object Model)
  3. 构建Render True

    • link元素不会阻塞DOM Tree的构建过程,但是会阻塞Render Tree的构建过程,因为RenderTrue在构建时,需要对应的CSSOM Tree
    • Render Tree和Dom Tree并不是完全对应关系,例如元素的display为none时,则该元素不会出现在Render Tree中
  4. 布局(layout),在渲染树(Render Tree)上运行布局(Layout)以计算每个节点的几何体

    • 渲染树会表示显示哪些节点以及其他样式,但是不表示每个节点的尺寸,位置等信息
    • 布局是确定呈现树中所有节点的宽度,高度和位置信息
  5. 绘制(Paint)

    • 浏览器将布局阶段的每个frame转为屏幕上实际的像素点
    • 包括将像数的可见部分进行绘制,比如文本,颜色,边框,替换元素(如img)等

3.回流和重绘

1.回流

1.定义 回流reflow(也可以称之为重排)
  • 第一次确定节点的大小和位置,称之为布局(layout)
  • 之后对节点的大小,位置修改重新计算称之为回流
2.引发回流的情况
  • DOM机构发生改变(添加新的节点或者移除节点)
  • 改变了布局(修改了width,height,padding,font-size等)
  • 窗口resize(修改了窗口的尺寸等)
  • 调用了getComputedStyle方法获取尺寸,位置信息

2.重绘

1.定义 重绘repaint
  • 第一次渲染内容称之为绘制(paint)
  • 之后重新渲染称之为重绘
2.引发重绘的情况
  • 修改背景颜色,文字颜色,边框颜色,样式等

3.结论

回流一定会引起重绘,所以回流是一件很消耗性能的事情,在开发中要尽量避免引发回流

注意:

  • 修改样式尽量一次性修改
  • 尽量避免频繁操作DOM
  • 尽量避免通过getComputedStyle获取尺寸,位置等信息
  • 对某些元素使用position的absolute或fixed(并不是不会引起回流,而是开销相对较小)

4.script元素与页面解析关系

  • 浏览器在解析HTML的过程中,遇到script元素是不能继续构建DOM树的
  • 会先下载js代码,并且执行js脚本,等到js脚本执行结束才会继续解析HTML,构建DOM树

为什么浏览器在遇到js代码时会优先下载并执行js暂停对HTML的解析?

  • js的作用之一就是操作DOM,并且可以修改DOM
  • 如果等到DOM树构建完成并且渲染再执行js代码,就会造成严重的回流和重绘,影响页面的性能

5.defer与 async

在目前的开发模式中(vue,react),脚本往往比HTML页面更“重”,处理时间更长,会造成页面解析阻塞,在脚本下载,执行完成前,用户在页面上什么都看不到。

为了解决这个问题,script元素给我们提供了两个属性(attribute):defer和async

1.defer

使用:

当我们在script中使用了defer后:

  • js文件的下载和执行,不会影响后面DOM Tree的构建
  • 如果脚本提前下载结束,它会等待DOM Tree构建完成,在DOMContentLoaded事件之前先执行defer中的代码
  • 多个带defer的脚本是可以保持正常执行顺序的
  • 从某种角度来说,defer可以提高页面的性能,并且推荐放到head元素中

注:defer仅适用于外部脚本,对于script默认内容会被忽略(在body中编写的js语句)

2.async

使用:

当我们在script中使用了async后:

  • 浏览器不会因async脚本而阻塞(与defer类似)
  • async脚本不能保证顺序,他是独立下载,独立运行,不会等待其它脚本
  • async不能保证在DOMContentLoaded之前或者之后执行

3总结

  • defer通常用于需要在文档解析后操作DOM的js代码 ,并且对多个js文件有顺序要求
  • async通常用于独立脚本,对其他脚本,甚至DOM没有依赖的

注:关于DOMContentLoaded可以看这篇:(blog.csdn.net/qq_32682137…)