前端性能优化由于涉及到计算机网络、数据算法、图形图像处理、浏览器渲染等多方面计算机知识,常做为前端工程师乐此不疲的技术讨论话题,也正因如此,它也是面试时容易被问及的面试题之一。css
本篇文章缘起一次偶然的面试问答所引伸出的思考整理,着笔于浏览器渲染的角度,探讨前端性能优化的思路和实践建议,固然,浏览器渲染是一个复杂的过程,本文笔者将围绕重排和重绘两个关键词开始行文。html
文章大体行文思路以下:前端
URL从输入到页面展现的过程web
DOM和JavaScript的关系面试
为何操做DOM会很“慢”算法
浏览器解析HTML的过程api
重排数组
重绘浏览器
优化方案缓存
在探讨浏览器解析html以前,先了解url从输入到最后页面渲染的过程是一个颇有必要的步骤,它能够帮助咱们把握总体流程,让咱们在了解HTML解析细节以前知道它处于整个请求周期中的哪一阶段,这对咱们构建完善知识图谱颇有帮助。
首先,咱们假设输入的url的请求为最简单的Http请求,以GET请求为例,大体分如下几个步骤:
用户在浏览器的地址栏输入访问的URL地址。浏览器会先根据这个URL查看浏览器缓存-系统缓存-路由器缓存,若缓存中有,直接跳到第6步操做,若没有,则按照下面的步骤进行操做。
浏览器根据输入的URL地址解析出主机名。
浏览器将主机名转换成服务器ip地址。浏览器先查找本地DNS缓存列表,看缓存里面是否存在这个ip,若是有则进入第4步,若是缓存中不存在这个ip地址,就再向浏览器默认的DNS服务器发送查询请求,同时缓存当前这个ip到DNS缓存列表中。更详细步骤参考DNS查找域名的过程。
拿到ip地址后,浏览器再从URL中解析出端口号。
拿到ip和端口后,浏览器会创建一条与目标Web服务器的TCP链接,也就是传说中的三次握手。传送门:完整的tcp连接。
浏览器向服务器发送一条HTTP请求报文。
服务器向浏览器返回一条HTTP响应报文。
关闭链接 浏览器解析文档。
若是文档中有资源则重复六、七、8动做,直至资源所有加载完毕。
以上步骤简述了浏览器从输入url到最后页面呈现的大体过程,但这并不很具体,好比浏览器请求报文类型是什么,会遇到哪些错误场景、浏览器又是如何解析响应报文等等都没具体描述。
实际上在http请求方式不一样、有无代理、有无负载均衡等不一样场景下访问服务器的细节流程也会有一些差异,但这并不影响咱们对整个访问环节的理解,有兴趣的同窗可网上自行详细了解,在此不作详述。
文档对象模型(DOM)是一个独立于语言,用于操做XML和HTML文档的API,在web端,咱们经常使用来操做HTML,但其实DOM也是能够操做XML文档的。
咱们如今知道,DOM是一个独立于语言的API,换句话说,DOM是一个与语言无关的API,别的语言也能够实现操做DOM的具体api,可是它在浏览器中是用JavaScript来实现的,也所以,DOM是如今JavaScript编码中很重要的一部分,由于JavaScript不少时候都在操做底层文档。
虽然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被HTML解析器解析成DOM Tree, css则被css解析器解析成CSSOM Tree。
DOM Tree和CSSOM Tree解析完成后,被附加到一块儿,造成渲染树(Render Tree)。
节点信息计算(重排),这个过程被叫作Layout(Webkit)或者Reflow(Mozilla)。即根据渲染树计算每一个节点的几何信息。
渲染绘制(重绘),这个过程被叫作(Painting 或者 Repaint)。即根据计算好的信息绘制整个页面。
以上4步简述浏览器的一次渲染过程,理论上,每一次的dom更改或者css几何属性更改,都会引发一次浏览器的重排/重绘过程,而若是是css的非几何属性更改,则只会引发重绘过程。因此说重排必定会引发重绘,而重绘不必定会引发重排。
在弄明白什么是重排以前,咱们要知道:浏览器渲染页面默认采用的是流式布局模型(Flow Based Layout),这一点很重要。
所谓重排,其实是根据渲染树中每一个渲染对象的信息,计算出各自渲染对象的几何信息(DOM对象的位置和尺寸大小),并将其安置在界面中的正确位置。
因为浏览器渲染界面是基于流式布局模型的,也就是某一个DOM节点信息更改了,就须要对DOM结构进行从新计算,从新布局界面,再次引起回流,只是这个结构更改程度会决定周边DOM更改范围,即全局范围和局部范围,全局范围就是从根节点html
开始对整个渲染树进行从新布局,例如当咱们改变了窗口尺寸或方向或者是修改了根元素的尺寸或者字体大小等;而局部布局能够是对渲染树的某部分或某一个渲染对象进行从新布局。
在此,总结会引发重排的操做有:
页面首次渲染。
浏览器窗口大小发生改变。
元素尺寸或位置发生改变。
元素内容变化(文字数量或图片大小等等)。
元素字体大小变化。
添加或者删除可见的DOM元素。
激活CSS伪类(例如::hover)。
设置style属性
查询某些属性或调用某些方法。
常见引发重排属性和方法 | |||
---|---|---|---|
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几何属性发生改变的时候,文档流会受到波动联动的去更改,流就比如一条河里的水,回流就比如向河里扔了一块石头,激起涟漪,而后引发周边水流受到波及,因此叫作回流,这样理解彷佛更标准更规范,不过叫什么并不重要,重要的是咱们真正理解了这个过程便好。
相比重排,重绘就简单多了,所谓重绘,就是当页面中元素样式的改变并不影响它在文档流中的位置时,例如更改了字体颜色,浏览器会将新样式赋予给元素并从新绘制的过程称。
常见引发浏览器绘制过程的属性包含:
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、暂存引用、减小重排、开启硬件加速等)。
最后,因为我的水平缘由,如有行文不全或疏漏错误之处,恳请各位读者批评指正,一路有你,不胜感激!
感谢这个时代,让咱们能够站在巨人的肩膀上,窥探程序世界的宏伟壮观,我愿以一颗赤子心,踏遍程序世界的千山万水!愿每个行走在程序世界的同仁,都活成心中想要的样子,加油。