回流线系列
产品展示
当前位置 >> 首页 > 产品中心 > 回流线系列

服务热线:0755 28160800
地址:中国 深圳市 宝安区石岩
      街道水田社区第二工业区
业务直线电话:
(86)0755-28160800
(86)0755-29839665
(86)0755-29839692
业务传真:(86)755 2344-2951
前台电话:(86)0755-29839341 
前台传真:(86)755-2983-9345
邮箱:ytsales@www.ecccar.com

前端渲染过程及重绘回流探究
发布时间:2022-01-22 10:55:47 来源:亿百体育 作者:亿百体育官方 [返回]

   

  记得前几个月小伙伴准备跳槽的时候,建议他可以准备下“从输入URL到页面加载发生了什么”这个前端面试常见问题。结果真的命中了两次。后来仔细思考,中间的确也反应出了很多知识点。如果能把整个过程弄懂,并且熟悉里面的所有知识,也的确能算一个中级前端工程师了。看了下网上的最详细版答案,发现自己主要不明白的地方在于渲染过程这一块。

  以前理解的前端渲染(非异步的情况),是在服务器返回首屏内容后,浏览器从上到下边解析边渲染整个response,其中如果为mvvm前端框架进行渲染,则会先将首屏渲染完成,然后执行js代码,交由框架进行渲染(这里具体又分为虚拟dom和双向绑定等,本次不谈及这块)。但后来深入了解后,才发现细节远不止这些。

  正如上面图片显示的流程一样,浏览器拿到全部代码之后,并不会直接从上到下进行渲染,而是将html和css抽分开来进行渲染成dom树(html结构树)和样式结构体(css结构树),等两个都渲染完成,再一并合成带样式的dom树,然后再根据树的具体内容,绘制成页面进行显示。这其中涉及到了前端首屏加载优化和重绘回流等问题。

  在写页面的时候,大多都是将css放在head里面,而将js丢到body的最下面,原因是不要让js阻塞整个页面的首屏渲染,让白屏时间不要太长。因此大量数据的页面,如今大多通过异步加载的形式进行优化。其原理是通过先出现个大概轮廓,显示一个加载中的图标,让用户有耐心等待下去。甚至包括现如今较为火热的移动端和app,也出了骨架屏这一概念(通过先渲染出大概轮廓,然后再慢慢显示数据,首先渲染出来的大概轮廓最近被称为骨架屏)。其原理也是白屏时间不宜太长。

  但其实当初看到这个优化办法的时候,自己内心一直有个疑问,为什么只把js丢下面,css不能也丢下去,先渲染出无样式的页面,再等待页面加载,这样不更能缩短白屏时间吗?而这个问题的答案就在上面的渲染流程中。页面渲染必定会先经过渲染css,即使放在下方,css也会阻塞整个页面的渲染。为此我做了个实验,将css阻塞2s再进行返回,然后将css置于body底部进行加载,整个页面果然白屏了2s。当然,针对这一问题,网上已经有很多解决方案,比如通过改变载入的link标签的media属性(当media属性不符合当前的时候,css会加载,但不会阻塞到当前页面,所以当css加载完毕后触发其onload事件改写media即可,不过经社区有人测试发现在ie和ff中会失败),以及开源项目loadCSS(原理相近,基本都是通过修改media或者js添加link标签进行解决)等。

  理解了整个渲染流程,其实对于渲染优化便能更得心应手了。无论是懒加载、异步加载、预加载等一系列名词,其实无非也就是针对首屏、白屏等时间进行优化。

  这两个问题也应该归于渲染优化,回流和重绘分别对应的便是前端渲染流程中的结合dom(html结构树)和cssom(css结构树)成为一个带样式的dom结构,以及将这一结构树渲染成我们所看到的页面这两个步骤。而在初次渲染的时候,这些操作都是一步完成。但在用户与web页面进行交互的时候,如果出现了对dom结构的操作(删除或修改),也会出发回流,即重新构建dom结构,然后再重绘。而如果单纯只是修改样式,则会产生重绘。

  因此,如果用户在操作过程中涉及到大量的修改dom操作,即会触发多次回流。为了优化性能,一般的做法是尽量减少非必要的触发回流的行为(如重复获取style信息),而针对不可避免的操作,则可以尽量放在一起。浏览器针对这一问题有个优化,会维护一个队列,将所有引起回流和重绘的操作放在里面,达到一定数量或间隔再一次性执行。

  除此以外,react中的虚拟dom概念其实也有助于减少回流。react中维护了一套与真实dom相同的虚拟dom。如果有涉及重绘回流的操作,会先在虚拟dom中完成,再一次性改变到真实dom中。