1000字范文,内容丰富有趣,学习的好帮手!
1000字范文 > 服务端(前端)| 从页面渲染谈性能优化

服务端(前端)| 从页面渲染谈性能优化

时间:2022-02-02 20:00:09

相关推荐

服务端(前端)| 从页面渲染谈性能优化

浏览器的主要功能是向服务器发出请求,在浏览器窗口中展示要访问的网络资源,主要组件包括:

✨用户界面;

✨浏览器引擎(在用户界面和渲染引擎之间传送指令);

✨渲染引擎(负责显示请求的内容。如果请求的内容是html,它就负责解析html和Css内容,并将解析后的内容显示在屏幕上);

✨网络(用于网络调用,比如http请求);

✨用户界面后端,用于绘制基本的窗口小部件,比如组合框和窗口;

✨JavaScript解释器,用于解析和执行JavaScript代码;

✨数据存储,浏览器需要在硬盘上保存各种数据,比如cookie。

渲染引擎

渲染引擎的职责就是渲染,即在浏览器窗口中显示所请求的内容,这是每一个浏览器的核心部分,所以渲染引擎也称为浏览器内核。

默认情况下,渲染引擎可显示HTML和XML文档及图片,通过插件渲染引擎也可以显示其他类型的内容。

浏览器的渲染引擎工作流程可大致分为5步:

✨创建DOM树:用HTML分析器,分析HTML元素,构建一颗DOM树。

✨创建StyleRules:用CSS分析器,分析CSS文件和元素上的inline样式,生成页面的样式表。

✨创建Render树:将DOM树和样式表关联起来,构建一个Render树,每个DOM节点都有attach方法,接受样式信息,返回一个Render对象。这些Render对象最终会被构建成一颗Render树。

✨布局Layout:有了Render树,浏览器开始布局,为每个Render树上的节点确定一个在屏幕上出现的精确坐标

✨绘制Painting:Render树和节点显示坐标都拥有了,就调用每个节点paint方法,把他们绘制出来。

图1 Webkit渲染引擎工作流程

重排与重绘

一旦DOM和渲染树构建完成,浏览器就开始显示(绘制“paint”)页面元素。

当DOM的变化影响了元素的几何属性(宽和高),比如改变边框宽度或给段落增加文字,导致行数增加,浏览器需要重新计算元素的几何属性,同样其他元素的几何属性和位置也因此受到影响。浏览器会使渲染树中受到影响的部分失效,并重新构造渲染树,这个过程称为重排(reflow)

完成重排后,浏览器会重新绘制受影响的部分到屏幕上,该过程称为重绘(repaint)

并不是所有的DOM变化都会影响几何属性

例如,只改变元素的背景色的情况下,只会发生一次重绘(不需要重排),因为元素的布局并没有改变。重绘和重排操作都是代价昂贵的操作,它们会导致Web应用程序的UI反应迟钝,所以应当减少这类过程的发生。

重排何时发生

✨添加或删除可见的DOM元素。

✨元素位置改变。

✨元素尺寸改变(包括:外边距、内边距、边框厚度、宽度、高度等属性改变)。

✨内容改变。

✨计算offsetWidth 和offsetHeight属性。

✨浏览器窗口尺寸改变,resize事件发生时。

No.1

减少重排影响的范围

由于浏览器渲染界面是基于流式布局模型的,所以触发重排时会对周围DOM重新排列,影响的范围有两种:

✨全局范围:从根节点html开始对整个渲染树进行重新排列。

✨局部范围:对渲染树的某部分或某一个渲染对象进行重新布局。把一个DOM的宽高之类的几何信息定死,然后在dom内部触发重排,就只会渲染该dom内部的元素,而不会影响到外界。

为了减少重排的影响范围,我们应该尽量以局部布局的形式组织html结构,尽可能小的影响重排的范围,而不是单纯的堆砌标签,导致随便一个元素触发重排都会导致全局返回的重排。

No.2

避免使用强制刷新渲染队列的属性及方法

由于每次重排都会产生计算消耗,多数浏览器通过队列化修改批量执行来优化重排过程,然而,你可能会强制刷新队列并要求计划任务立刻执行,获取布局信息的操作会导致队列刷新,比如以下方法:

offsetTop

offsetLeft

offsetWidth

offsetHeight

scrollTop

scrollLeft

scrollWidth

scrollHeightc

clientTop

clientLeft

clientWidth

clientHieght

getComputedStyle()

以上属性和方法需要返回最新的布局信息,因此浏览器不得不执行渲染队列中的“待处理变化”并触发重排以返回正确的值。在修改样式的过程中,最好避免使用上面列出的属性。

No.3

减少重排和重绘的次数

为了减少重排和重绘的发生次数,应该合并多次对DOM和样式的修改,然后一次处理掉。

No.4

批量修改DOM

当你需要对DOM元素进行一系列操作时,可以通过使DOM脱离文档,经过多次改变后再放回文档来减少重绘和重排的次数:

No.5

缓存布局信息

浏览器尝试通过队列化修改和批量执行的方式最小化重排次数。当你查询布局信息时,比如获取偏移量(offsets)、滚动位置(scroll values)或计算出的样式值时,浏览器为了返回最新值,会刷新队列并应用所有变更,最好的做法是尽量减少布局信息获取的次数,获取后把它复制给局部变量,然后再操作局部变量:

No.6

优化动画

把动画效果应用到position属性为absolute或fixed的元素上,这样对其他元素影响较小;

动画效果还可以考虑牺牲一些平滑,来换取速度,比如实现一个动画,以1个像素为单位移动最为平滑,但reflow就会过于频繁,大量消耗CPU资源,可以考虑以3个像素为单位;

启动图像加速器(GPU),GPU是专为处理图形而设计,所以在速度和能耗上更有效率。GPU加速通常包括以下部分:Canvas2D,布局合成,CSS3转换(transitions),CSS3 3D转换(transforms),WebGLS和视频video。

虚拟DOM

我们减少页面重排(重绘)的核心是最小化DOM的改变,以此来减少重新渲染页面带来的影响。

另外一种最小化DOM操作的方式是使用虚拟DOM。虚拟DOM可以对JavaScript操作DOM进行优化,若一次操作中有多次更新DOM的动作,虚拟DOM不会立即操作DOM,而是将多次更新的diff内容保存到本地一个JS对象中,最终将这个JS对象一次性attach到DOM树上,再进行后续操作,避免大量无谓的计算量,并且操作内存中的JS对象的速度显然要更快,等更新完成后,再将最终的JS对象映射成真实的DOM,交由浏览器绘制。

具体包括以下几个步骤:

✨用JavaScript对象表示DOM树的结构,然后用这个树构建一个真正的DOM树,插入到文档中。用JavaScript对象模拟一个DOM节点只需要记录它的节点类型(tagName)、属性(props)、子节点(children)。

✨当状态变更的时候,重新构造一个新的对象树,然后用这个新的树和旧的树作对比,记录两个树的差异。比较两颗DOM树的差异是虚拟DOM的diff算法。两个树完全的diff算法是个时间复杂度为O(n3)的问题,但是在前端中很少跨层移动DOM,所以真实的DOM算法会对同一级的元素进行对比,这样算法的复杂度就可以达到O(n)。

✨把步骤二中所记录的差异应用在步骤一所构建的真正的DOM树上,视图完成更新。

现在主流框架Vue.js和React都是用了虚拟DOM来实现视图更新。不同的是Vue在渲染过程中,会跟踪每一个组件的依赖关系,不需要重新渲染整个组件树。而对于React而言,每当应用的状态被改变时,全部子组件都会重新渲染,不过可以通过shouldComponentUpdate这个生命周期来进行控制。

长按下方二维码关注我们

途牛技术中心

期待与你相逢

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。