斗地主怎样记牌|宋小宝斗地主搞笑视频
登录 立即注册
金钱:

Code4App-iOS开发-iOS 开源代码库-iOS代码实例搜索-iOS特效示例-iOS代码例子下载-Code4App.com

让你的网页更丝滑(一) [复制链接]

2019-5-7 21:05
2899926939 阅读:122 评论:0 赞:0
Tag:  

前段时间,我将精力专注在Web性能领域;在这个领域下有个重要的课题是如何让网页更丝滑(流畅)。

想让网页变得丝滑,首先,我们需要一个标准来判断什么样的网页是丝滑的;其次,我们要准确的测量出网页的性能数据;最后,使用有效的方法让网页变得丝滑。

本篇文章将针对这三个方面进行详细的介绍。

如果你依然在编程的世界里迷茫,不知道自己的未来规划,小编给大家推荐一个iOS高级交流群:458839238 里面可以与大神一起交流并走出迷茫。小?#21331;?#36827;群免费领取学习资料,看看前辈们是如何在编程的世界里傲然前行!
群内提供数据结构与算法、底层进阶、swift、逆向、整合面试题?#35753;?#36153;资料

附上一份收集的各大厂面试题(附答案) ! ?#20309;?#20214;直接获取
各大厂面试题

1. RAIL

到?#33258;?#26679;的网页是丝滑的?我们需要一个标准来辅助判断我们的网页是否丝滑。

Chrome团队提出了一个以用户为?#34892;?#30340;性能模型被称为RAIL,它为工程师提供一个目标,只要达到目标的网页,用户就会觉得很流畅;它将用户体验拆解为一些关键操作,例如:点击,加载等;并给这些操作规定一个目标,例如:点击一个按钮后,多长时间给反馈用户会觉得流畅。

RAIL将影响性能的行为划分为四个方面,?#30452;?#26159;:Response响应、Animation动画、Idle空闲 与Load加载。没错,RAIL这个名字来自于这四个单词的首字母,方便记忆。

1.1 响应Response

研究表明,100ms内对用户的输入操作进行响应,通常会被人类认为是立即响应。时间再长,操作与反应之间的连接就会中断,人们就会觉得它的操作有延迟。例如:当用户点击一个按钮,如果100ms内给出响应,那么用户就会觉得响应很及时,不会察觉到丝毫延迟?#23567;?/p>

1.2 动画Animation

现如今大多数设备的屏幕刷新频率是60Hz,也就是每秒钟屏幕刷新60次;因此网页动画的运行速度只要达到60FPS,我们就会觉得动画很流畅。

FFrames PPer SSecond指的画面每秒钟传输的帧数,60FPS指的是每秒钟60帧?#25442;?#31639;下来每一帧差不多是16毫秒。

(1 秒 = 1000 毫秒) / 60 帧 = 16.66 毫秒/帧
复制代码

但通常浏览器需要花费一些时间将每一帧的内容绘?#39057;?#23631;幕上(包括样式计算、布?#24103;?#32472;制、合成等工作),所以通常我们只有10毫秒来执行JS代码。

1.3 空闲Idle

为了更好的性能,通常我们会充分利用浏览器空闲周期Idle Period做一些低优先级的事情。例如:在空闲周期预请求一些接下来可能会用到的数据或上报分析数据?#21462;?/p>

RAIL规定,空闲周期内运行的任务不得超过50ms,当然不止RAIL规定,W3C性能工作组的Longtasks标准也规定了超过50毫秒的任务属于长任务,那么50ms这个数字是怎么得来的呢?

浏览器是单线程的,这意味着同一时间主线程只能处理一个任务,如果一个任务执行时间过长,浏览器则无法执行其他任务,用户会感觉到浏览器被卡死了,因为他的输入得不到任何响应。

为了达到100ms内给出响应,将空闲周期执行的任务限制为50ms意味着,即使用户的输入行为发生在空闲任务刚开始执行,浏览器仍有剩余的50ms时间用来响应用户输入,而不会产生用户可察觉的延迟。如图1-1所示:

图1-1

事实上,不论是空闲任务还是高优先级的其他任务,执行时间都不得超过50ms

1.4 加载Load

如果不能在1秒钟内加载网页并让用户看到内容,用户的注意力就会分散。用户会觉得他要做的事情被打断,如果10秒钟还打不开网页,用户会感到失望,会放弃他们想做的事,以后他们或许都不会再回来。

1.5 小结

通过RAIL,我们可以判断出我们的网页是否丝滑。RAIL从用户感知角度出发规定了一些指标,只要我们的网页符合标准,则我们的网页是丝滑的,用户会觉得我们的网页很流畅。

RAIL关键指标用户操作
响应(Response)小于100ms点击按钮。
动画(Animation)小于16ms滚动页面,拖动手指,播放动画?#21462;?/td>
空闲(Idle)小于50ms用户没有与页面交互,但应该保证主线程足够处理下一个用户输入。
加载(Load)1000ms用户加载页面并看到内容。

2. 像素管道

像素管道是制作丝滑网页的灵魂,我们后面将要介绍的技术都与它有关。

上图就是像素管道,通常我们会使用JS修改一些样式,随后浏览器会进行样式计算,然后进行布局,绘制,最后将各个图层合并在一起完成整个渲染的流程,这期间的每一步都有可能导致页面卡顿。

注意,并不是所有的样式改动都需要经历这五个步骤。举例来说:如果在JS?#34892;?#25913;了元素的几何属性(宽?#21462;?#39640;度等),那么浏览器需要需要将这五个步骤都走一遍。但如果您只是修改了文字的颜色,则布局(Layout)是可以跳过去的,如下图所示:

除了最后的合成,前面四个步骤在不同的场景下都可以被跳过。例如:CSS动画就可以跳过JS运算,它不需要执行JS。

css-triggers1给出了不同的CSS属性被更改后会触发像素管道的哪些步骤。

简单来说,像素管道经历的步骤越多,渲染时间就越长,单个步骤内可能?#19981;?#22240;为某种原因而变得耗时很长;所以不管是步骤多还是单个步骤耗费的时间长,最终都会导致整体渲染时间变长。整体时间越长就越有可能超出RAIL所规定的指标。

举个简单的例子:网页动画的渲染若是达到60FPS,则动画不会丢帧。假设渲染管道的布局与绘制耗费了10ms,那么加上样式计算与合成的时间,则留给JS处理动画的时间就只有几毫秒,如果JS的执行超过了几毫秒那么该动画每一帧所耗费的时间就会超过16ms,这时候动画一定会丢帧,用户用肉眼就可以看到明显的卡顿。

当然,即便能保证每一帧的总耗时小于16ms,依然无法保证不会丢帧。关于这点后面我们会详细介绍。

3. 如何让动画更丝滑

动画需要达到60FPS才能变得丝滑,本节我们介绍如何让动画在不丢帧的情况下稳定保持在60FPS。

3.1 使用Chrome开发者工具测量动画性能

在评估动画性能时,通常需要逐帧评估像素管道的开销;使用 Chrome 开发者工具可以辅助我们进行精准的测量。

在Chrome开发者工具中,点击Performance面板,然后选中Screenshots复选框,。如图3-1所示:

图3-1Chrome开发者工具Performance面板

然后点击录制按钮,录制完毕后点击停止按钮就可以捕获当前页面的性能数据。如图3-2所示:

图3-2捕获性能数据

捕获出的结果如图3-3所示:

图3-3捕获出的性能结果

我们可以放大主线程从而精准的看到每一帧浏览器都执行了哪些任务以及每个任务耗费了多长时间。如图3-4所示:

图3-4性能面板最主要的部分

从上图可以看到,浏览器每一帧渲染所执行的任务与前面我们介绍的像素管道是相同的。上图中因为是CSS动画,所以没?#24615;?#34892;JS,但每一帧都需要计算样式、布?#24103;?#32472;制与合成。

3.2 如何让JS动画更丝滑

JS动画是使用定时器不停的执行JS,通过在JS?#34892;?#25913;样式完成网页动画;若想保证动画流畅,从JS的执行到最终浏览器显示出画面,每一帧总耗时最多16ms,这样动画才能达到60FPS。

如图3-4所示,即便是在不执行JS的情况下,浏览器计算样式、布?#24103;?#32472;?#39057;?#24037;作也是需要时间的,所以需要给浏览器预留出 充分的时间做这些事情,现在留给JS的执行时间就只有 10ms

图3-5每一帧总体耗时必须小于16ms,JS运行时间小于10ms

一旦JS运行时间超过10ms,就很有可能导致这一帧的像素管道整体耗时超过16ms,从而无法达到60FPS,但你以为只要保证JS的运行时间小于10ms就一定能保证不丢帧?Naive~

3.2.1 使用requestAnimationFrame

即便你能保证每一帧的总耗时都小于16ms,也无法保证一定不会出现丢帧的情况,这取决于触发JS执行的方式。

假设使用 setTimeoutsetInterval 来触发JS执行并修改样式从而导致视觉变化;那么会有这样一种情况,因为setTimeoutsetInterval没有办法保证回调函数什么时候执行,它可能在每一帧的中间执行,?#37096;?#33021;在每一帧的最后执?#23567;?#25152;以会导?#24405;?#20415;我们能保障每一帧的总耗时小于16ms,但是执行的时机如果在每一帧的中间或最后,最后的结果依然是没有办法每隔16ms让屏幕产生一次变化。如图3-6所示:

图3-6使用定时器触发动画

也就是说,即便我们能保证每一帧总体时间小于16ms,但如果使用定时器触发动画,那么由于定时器的触发时机不确定,所以还是会导致动画丢帧。现在整个Web只有一个API可以解决这个问题,那就是requestAnimationFrame,它可以保证回调函数稳定的在每一帧最开?#21363;?#21457;。如图3-7所示:

图3-7使用requestAnimationFrame触发动画

3.2.2 避免FSL

FSL Forced Synchronous Layouts被称为强制同步布局;前面介绍像素管道时说过,将一帧送到屏幕会通过如下顺序:

先执行JS,然后在JS?#34892;?#25913;?#25628;?#24335;从而导致样式计算,然后样式的改动触发了布?#24103;?#32472;制、合成。但JavaScript可以强制浏览器将布局提前执行,这就叫F 强制 S 同步 L 布局

图3-8强制同步布局

通常我们一不小心就造成了FSL,请看下面代码:

box.classList.add('big');
const width = box.offsetWidth;
复制代码

代码中通过新增class修改了元素的样式,随后使用offsetWidth读取元素的宽?#21462;?#20045;一看似乎没什么问题,但这段代码会导致FSL。

在 JavaScript 运行时,上一帧已经渲染好的所有布局值都是已知的,我们可以使用offsetWidth这样的语法获得值;但这一帧?#25307;?#25913;完的样式浏览器还没渲染呢,这时候使用offsetWidth这样的语法读取元素的宽度,那么浏览器为了告诉我们宽度值,它必须先计算?#27599;?#24230;,这就需要布?#24103;?#22914;图3-8所示,布局跑到?#25628;?#24335;计算的前面。

所以正确的做法是先获取宽度,然后再更改样式:

const width = box.offsetWidth;
box.classList.add('big');
复制代码

看起来,似乎即使触发了FSL也不过就是管道的顺序变了而已,影响好像并没有那么大。

分享到:
我来说两句
facelist
您需要登录后才可以评论 登录 | 立即注册
所有评论(0)
关闭

每日头条

通过邮件订阅最新 Code4App 信息
上一条 /4 下一条
联系我们
关闭
合作电话:
13802416937
Email:
[email protected]
商务市场合作/投稿
问题反馈及帮助
联系我们

广告投放| 广东互联网违法和不良信息举报?#34892;?/a>|中国互联网举报?#34892;?/a>|Github|申请友链|?#21482;?#29256;|Code4App ( 粤ICP备15117877号-1 )

返回顶部
斗地主怎样记牌 吃鸡游戏下载平台 宝石探秘玩法 时时彩9码平刷稳赚方案 北京11选5走势 刮刮乐电子游艺 川崎前锋vs东京绿茵 AC米兰 欧冠 美因茨大学格尔翻译学院 湖南幸运赛车走势图 星际大战游戏