前端性能优化:细说浏览器渲染的重排与重绘

原文链接 https://www.imooc.com/article/45936 侵删

图片描述

前端性能优化因为涉及到计算机网络、数据算法、图形图像处理、浏览器渲染等多方面计算机知识,常作为前端工程师乐此不疲的技术讨论话题,也正因如此,它也是面试时容易被问及的面试题之一。

缘起

本篇文章缘起一次偶然的面试问答所引申出的思考整理,着笔于浏览器渲染的角度,探讨前端性能优化的思路和实践建议,当然,浏览器渲染是一个复杂的过程,本文笔者将围绕重排和重绘两个关键词开始行文。

目录结构

文章大致行文思路如下:

  • URL从输入到页面展示的过程

  • DOM和JavaScript的关系

  • 为什么操作DOM会很“慢”

  • 浏览器解析HTML的过程

  • 重排

  • 重绘

  • 优化方案

URL从输入到页面展示的过程

在探讨浏览器解析html之前,先了解url从输入到最后页面渲染的过程是一个很有必要的步骤,它可以帮助我们把握整体流程,让我们在了解HTML解析细节之前知道它处于整个请求周期中的哪一阶段,这对我们构建完善知识图谱很有帮助。

首先,我们假设输入的url的请求为最简单的Http请求,以GET请求为例,大致分以下几个步骤:

  1. 用户在浏览器的地址栏输入访问的URL地址。浏览器会先根据这个URL查看浏览器缓存-系统缓存-路由器缓存,若缓存中有,直接跳到第6步操作,若没有,则按照下面的步骤进行操作。

  2. 浏览器根据输入的URL地址解析出主机名。

  3. 浏览器将主机名转换成服务器ip地址。浏览器先查找本地DNS缓存列表,看缓存里面是否存在这个ip,如果有则进入第4步,如果缓存中不存在这个ip地址,就再向浏览器默认的DNS服务器发送查询请求,同时缓存当前这个ip到DNS缓存列表中。更详细步骤参考DNS查找域名的过程

  4. 拿到ip地址后,浏览器再从URL中解析出端口号。

  5. 拿到ip和端口后,浏览器会建立一条与目标Web服务器的TCP连接,也就是传说中的三次握手。传送门:完整的tcp链接

  6. 浏览器向服务器发送一条HTTP请求报文。

  7. 服务器向浏览器返回一条HTTP响应报文。

  8. 关闭连接 浏览器解析文档。

  9. 如果文档中有资源则重复6、7、8动作,直至资源全部加载完毕。

以上步骤简述了浏览器从输入url到最后页面呈现的大致过程,但这并不很具体,比如浏览器请求报文类型是什么,会遇到哪些错误场景、浏览器又是如何解析响应报文等等都没具体描述。

实际上在http请求方式不同、有无代理、有无负载均衡等不同场景下访问服务器的细节流程也会有一些差别,但这并不影响我们对整个访问环节的理解,有兴趣的同学可网上自行详细了解,在此不做详述。

DOM和JavaScript的关系

文档对象模型(DOM)是一个独立于语言,用于操作XML和HTML文档的API,在web端,我们常用来操作HTML,但其实DOM也是可以操作XML文档的。

我们现在知道,DOM是一个独立于语言的API,换句话说,DOM是一个与语言无关的API,别的语言也可以实现操作DOM的具体api,但是它在浏览器中是用JavaScript来实现的,也因此,DOM是现在JavaScript编码中很重要的一部分,因为JavaScript很多时候都在操作底层文档。

为什么操作DOM会很慢

虽然DOM是由JavaScript实现的,但是在浏览器中都是把DOM和JavaScript分开来实现的,比如IE中,JavaScript的实现名为JScript,放在jscript.dll文件中,而DOM则放在另一个叫做mshtml.dll的库中。在Safari中,DOM和渲染是使用Webkit中的WebCore实现,而JavaScript是由独立的JavaScriptCore引擎实现,同样在Chrome中,同样是使用WebCore来实现渲染,而JavaScript引擎则是他们自己研发的V8引擎。

由于DOM和JavaScript是被分开独立实现的,因此,每一次在通过js操作DOM的时候,就需要先去连接js和DOM,我们可以这样理解:把DOM和JavaScript比作两个岛,他们之间通过一个收费的桥连接着,每一次访问DOM的时候,就需要经过这座桥,并且给“过路费”,访问的次数越多,路费就会越高,并且访问到DOM后,操作具体的DOM还需要给“操作费”,由于浏览器访问DOM的操作很多,因此,“路费”和“操作费”自然会增加,这就是为什么操作DOM会很慢的原因

浏览器渲染HTML的步骤

HTML渲染大致分为如下几步:

  1. HTML被HTML解析器解析成DOM Tree, css则被css解析器解析成CSSOM Tree。

  2. DOM Tree和CSSOM Tree解析完成后,被附加到一起,形成渲染树(Render Tree)。

  3. 节点信息计算(重排),这个过程被叫做Layout(Webkit)或者Reflow(Mozilla)。即根据渲染树计算每个节点的几何信息。

  4. 渲染绘制(重绘),这个过程被叫做(Painting 或者 Repaint)。即根据计算好的信息绘制整个页面。

以上4步简述浏览器的一次渲染过程,理论上,每一次的dom更改或者css几何属性更改,都会引起一次浏览器的重排/重绘过程,而如果是css的非几何属性更改,则只会引起重绘过程。所以说重排一定会引起重绘,而重绘不一定会引起重排。

重排(Relayout/Reflow)

在弄明白什么是重排之前,我们要知道:浏览器渲染页面默认采用的是流式布局模型(Flow Based Layout),这一点很重要。

所谓重排,实际上是根据渲染树中每个渲染对象的信息,计算出各自渲染对象的几何信息(DOM对象的位置和尺寸大小),并将其安置在界面中的正确位置。

由于浏览器渲染界面是基于流式布局模型的,也就是某一个DOM节点信息更改了,就需要对DOM结构进行重新计算,重新布局界面,再次引发回流,只是这个结构更改程度会决定周边DOM更改范围,即全局范围和局部范围,全局范围就是从根节点html开始对整个渲染树进行重新布局,例如当我们改变了窗口尺寸或方向或者是修改了根元素的尺寸或者字体大小等;而局部布局可以是对渲染树的某部分或某一个渲染对象进行重新布局。

在此,总结会引起重排的操作有:

  1. 页面首次渲染。

  2. 浏览器窗口大小发生改变。

  3. 元素尺寸或位置发生改变。

  4. 元素内容变化(文字数量或图片大小等等)。

  5. 元素字体大小变化。

  6. 添加或者删除可见的DOM元素。

  7. 激活CSS伪类(例如::hover)。

  8. 设置style属性

  9. 查询某些属性或调用某些方法。

常见引起重排属性和方法
width height margin padding
display border position overflow
clientWidth clientHeight clientTop clientLeft
offsetWidth offsetHeight offsetTop offsetLeft
scrollWidth scrollHeight scrollTop scrollLeft
scrollIntoView() scrollTo() getComputedStyle()
getBoundingClientRect() scrollIntoViewIfNeeded()

重排也叫回流,实际上,reflow的字面意思也是回流,之所以有的叫做重排,也许是因为重排更好理解,更符合中国人的思维。标准文档之所以叫做回流(Reflow),是因为浏览器渲染是基于“流式布局”的模型,流实际就使我们常说的文档流,当dom或者css几何属性发生改变的时候,文档流会受到波动联动的去更改,流就好比一条河里的水,回流就好比向河里扔了一块石头,激起涟漪,然后引起周边水流受到波及,所以叫做回流,这样理解似乎更标准更规范,不过叫什么并不重要,重要的是我们真正理解了这个过程便好。

重绘(Repainting)

相比重排,重绘就简单多了,所谓重绘,就是当页面中元素样式的改变并不影响它在文档流中的位置时,例如更改了字体颜色,浏览器会将新样式赋予给元素并重新绘制的过程称。

常见引起浏览器绘制过程的属性包含:

color border-style visibility background
text-decoration background-image background-position background-repeat
outline-color outline outline-style border-radius
outline-width box-shadow background-size

性能优化

我们知道操作DOM是一个高成本的操作,不仅是因为本身js与DOM的链接访问,还包括操作DOM后悔引起一连串的连锁反应(重排),因此,从性能优化角度,我们可以从以下几个方面着手:

  • 减少DOM操作

    • 最小化DOM访问次数,尽量缓存访问DOM的样式信息,避免过度触发回流。

    • 如果在一个局部方法中需要多次访问同一个dom,则先暂存它的引用。

  • 采用更优的API替代消费高的api,转换优化消费高的集合

    • 用querySelectorAll()替代getElementByXX()。

    • 开启动画的GPU加速,把渲染计算交给GPU。

    • 少用HTML集合(类数组)来遍历,因为集合遍历比真数组遍历耗费更高。

    • 用事件委托来减少事件处理器的数量。

  • 减少重排

    • 避免设置大量的style属性,因为通过设置style属性改变结点样式的话,每一次设置都会触发一次reflow,所以最好是使用class属性

    • 实现元素的动画,它的position属性,最好是设为absoulte或fixed,这样不会影响其他元素的布局

    • 动画实现的速度的选择。比如实现一个动画,以1个像素为单位移动这样最平滑,但是reflow就会过于频繁,大量消耗CPU资源,如果以3个像素为单位移动则会好很多。

    • 不要使用table布局,因为table中某个元素旦触发了reflow,那么整个table的元素都会触发reflow。那么在不得已使用table的场合,可以设置table-layout:auto;或者是table-layout:fixed这样可以让table一行一行的渲染,这种做法也是为了限制reflow的影响范围

  • css及动画处理

    • 少用css表达式

    • 减少通过JavaScript代码修改元素样式,尽量使用修改class名方式操作样式或动画;

    • 动画尽量使用在绝对定位或固定定位的元素上;

    • 隐藏在屏幕外,或在页面滚动时,尽量停止动画;

最后总结

本篇文章主要抓取url从输入到最后渲染成界面这一流程中的浏览器解析渲染HTML这一步骤来探讨前端优化的思路和原因,核心思想基于重排和重绘的关系来展开讨论,主题大致有如下几点:

  • url从输入到最后渲染的大致环节。

  • 重排一定会重绘,重绘不一定有重排。

  • Js操作DOM是一个高消费过程。

  • 会引起重排/重绘的属性和方法列举

  • 优化思路(减少dom操作、替换高性能api、暂存引用、减少重排、开启硬件加速等)。

最后,由于个人水平原因,若有行文不全或疏漏错误之处,恳请各位读者批评指正,一路有你,不胜感激!

作者:小白师兄
链接:https://www.imooc.com/article/45936
来源:慕课网
本文原创发布于慕课网 ,转载请注明出处,谢谢合作

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,569评论 4 363
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,499评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,271评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,087评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,474评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,670评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,911评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,636评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,397评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,607评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,093评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,418评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,074评论 3 237
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,092评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,865评论 0 196
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,726评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,627评论 2 270