让我们来瞧瞧在滚动时到底发生了什么。在理解这个问题之前,我们先简要的介绍下浏览器是如何向屏幕绘制内容的。这一切都是从 DOM 树(本质上就是页面中的所有元素)开始的。浏览器先检查拥有了样式的 DOM,然后找到那些它认为在滚动时不会改变的元素,然后将这些元素分组并对它们拍照(也就是层)。这些层都需要绘制并栅格化为一个纹理,然后混合在一起成为你在屏幕上看到的图像。

 
 
当滚动页面时,浏览器很可能需要在这些层(有时称为复合层,即 compositor layers)上绘制一些像素点。通过将内容分组为层后,当某个特定的层内发生改变,我们只需更新该层的纹理,并且只绘制和栅格化渲染层的纹理中被损坏的部分,而不必绘制所有内容。很显然,如果你在滚动过程中移动了某些内容,就像视差网站那样,你就可能损坏一大片区域,很大程度上会涉及多个层,结果就是会造成耗费严重的绘制工作。
 
简而言之,越少绘制越好。
 
如果你打开时间轴面板,设置成 frame 模式,点击记录(record)按钮并开始滚动页面,你将会看到一堆绿柱。在时间轴下的列表中,你会看到全部绘制堆的记录。它们就是 Chrome 在为页面的混合层绘制与栅格化纹理。(在绘制工作结束后,你可能会看到一些复合层的记录,它们就是更新后的层,为显示在屏幕上做好了复合的准备。)
 
紧挨着绘制记录的是绘制的区域,你把鼠标放到上面,Chrome 会高亮页面中重绘的区域。另一种查看重绘区域的方法是在 Chrome 开发者工具的设置页面(点击工具右上角的小齿轮进入)开启 “Show paint rectangles”。这是用来了解滚动时页面表现的第一个指示器。提示:应该尽可能的使绘制区域最小化。
 
当侧边栏显示时,你会看到绘制的区域就是整个屏幕,导致性能很差。造成这种情况的原因是 Chrome 对受损区域做了并集。本例中,在内容区上方,宽度为 100% 的带状区域进入视野中,而高度为 100% 的侧边栏也被绘制进了同样的复合层内,这些区域合并在一起就成了一个 100% 宽和 100% 高的区域。如果你用页面上方的复选框来禁用侧边栏,再次滚动你会发现重绘的仅仅是顶部的带状区域,响应速度更快了。
 
如果你想看个真实例子,就打开 Google+,将侧导航栏从 position: fixed 修改为 position: absolute。当然了,这就改变了网站的行为,但要点在于,你能看到一个通过切换样式来达到性能提升的真实例子。可能当你看到这之后的第一反应就是决定以后再也不用 position:fixed 了,但这与所在环境和需求有关。任何东西都有它适用的地方,重要的是能够测量并理解你的决定所造成的影响。
 
除了能看到基本的绘制记录,实际上我们还能得到额外的一些信息,特别是和图片相关的。如果你在记录过程中上下调整页面大小,就会看到有些绘制记录允许你打开它来获得更多细节,然后你就应该看到改变图片尺寸的记录。也就是说:浏览器将调整图片尺寸作为渲染工作的一部分。需要浏览器重新调整尺寸的图片个数和触发的频率会影响页面的性能,因为它们发生在主浏览器线程,会阻碍其他操作。
 
另外也会影响滚动性能的
耗性能样式
不同样式在消耗性能方面是不同的,有些效果(如经常被人提起的 box-shadow)从渲染角度来讲十分耗性能,原因就是与其他样式相比,它们的绘制代码执行时间过长。这就是说,如果一个耗性能严重的样式经常需要重绘,那么你就会遇到性能问题。其次你要知道,没有不变的事情,在今天性能很差的样式,可能明天就被优化,并且浏览器之间也存在差异。因此关键在于,你要借助开发工具来分辨出性能瓶颈所在,然后设法减少浏览器的工作量。
 
重排与重绘
无论何时你在 JavaScript 中获取元素的 offsetTop 属性,就相当于立即为浏览器布置了大量任务,它必须马上布局页面来为你返回正确答案。这个过程就称为重排。当我们基于 offsetTop 的值来改变元素的其他属性,那么元素(还有它的复合层)就需要重绘。它还会带来一个连锁反应,即由于重绘而导致 offsetTop 的值失效,因为对浏览器来说,页面发生了变化。
当你对多个元素做上述操作时就可能引发严重问题。如果我们为每个元素计算位置然后重绘它,就会使浏览器进入耗能高且浪费的重排-重绘周期中。在这种情况下,我们应该通过两个步骤来减少周期:首先,收集元素的 offsetTop 值,然后,完成视觉更新。通过这样的方式,我们就避免了重复计算元素的位置,假设我们使用 requestAnimationFrame,那么就可以让视觉更新按照浏览器的最优时间来安排计划。
值得一提的是,除了 offsetTop 之外的其他操作也会引起重排 http://gent.ilcore.com/2011/03/how-not-to-trigger-layout-in-webkit.html,最好了解一下这些内容来提高警惕。
 
反跳滚动事件(Debouncing Scroll Events)
假设你正开发一个视差滚动网站。你很自然的想到在获得滚动事件时对视觉进行更新。主要的问题在于滚动事件和浏览器的视觉更新并不合拍,比如说在 requestAnimationFrame 的回调函数中,就会出现在一个渲染帧内多次更新的风险。如果更新操作耗费很高,视差滚动网站通常都会如此(大量被破坏的区域,很多重绘与组合操作),那么这些重复操作就很浪费。要解决这一问题,你需要反跳滚动事件。当滚动事件触发时你就把上一次滚动的值保持在变量中,然后在 requestAnimationFrame 中执行视觉更新,使用最后已知的那个值。如此一来,浏览器可以在正确的时间里来安排视觉更新,而我们在每一帧中都只做必要的工作。
 
我们在之前一篇文章中介绍过重排/重绘周期,如果想了解更多内容不放看看这篇文章。

scrolling 优化 避免卡顿的更多相关文章

  1. android问题及其解决-优化listView卡顿和怎样禁用ListView的fling

    问题解决-优化listView卡顿和怎样禁用ListView的fling 前戏非常长,转载请保留出处:http://blog.csdn.net/u012123160/article/details/4 ...

  2. 性能优化 BlockCanary 卡顿监测 MD

    Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...

  3. Android 卡顿优化 1 卡顿解析

    1, 感知卡顿 用户对卡顿的感知, 主要来源于界面的刷新. 而界面的性能主要是依赖于设备的UI渲染性能. 如果我们的UI设计过于复杂, 或是实现不够好, 设备又不给力, 界面就会像卡住了一样, 给用户 ...

  4. iOS应用千万级架构:性能优化与卡顿监控

    CPU和GPU 在屏幕成像的过程中,CPU和GPU起着至关重要的作用 CPU(Central Processing Unit,中央处理器) 对象的创建和销毁.对象属性的调整.布局计算.文本的计算和排版 ...

  5. apm 应用性能管理(启动优化/ 掉帧卡顿/ 耗电/ 内存泄漏等)

    APM 首先查看各个阶段耗时 : (环境变量设置 dyldPRINTSTATISTICS = 1选项,) 1. 启动优化 关键: 找到耗时的原因 t总 = t1 (premain) + t1(main ...

  6. 字节跳动 iOS Heimdallr 卡死卡顿监控方案与优化之路

    点这里申请 本文主要介绍Heimdallr对卡死.卡顿异常的监控原理,并结合长时间的业务沉淀发现的问题进行不断迭代和优化,逐步实现全面.稳定.可靠的历程. 作者:字节跳动终端技术--白昆仑 前言 卡死 ...

  7. 4.Android App 优化之消除卡顿

    转载:http://gold.xitu.io/post/582583328ac247004f3ab124 1, 感知卡顿 用户对卡顿的感知, 主要来源于界面的刷新. 而界面的性能主要是依赖于设备的UI ...

  8. ViewPager -- Fragment 切换卡顿 性能优化

    当ViewPager切换到当前的Fragment时,Fragment会加载布局并显示内容,如果用户这时快速切换ViewPager,即 Fragment需要加载UI内容,而又频繁地切换Fragment, ...

  9. Android app 性能优化的思考--性能卡顿不好的原因在哪?

    说到 Android 系统手机,大部分人的印象是用了一段时间就变得有点卡顿,有些程序在运行期间莫名其妙的出现崩溃,打开系统文件夹一看,发现多了很多文件,然后用手机管家 APP 不断地进行清理优化 ,才 ...

随机推荐

  1. struts2一个和多个文件上传及下载

    struts2的文件上传相比我们自己利用第三方jar包(commons-fileupload-1.2.1.jar   commons-io-1.3.2.jar )要简单的多,当然struts2里面也是 ...

  2. 第1回-使用ThinkPHP的3.1.3版本轻松建网站

    使用ThinkPHP的3.1.3版本轻松建网站 首先,从ThinkPHP官网下载一个ThinkPHP3.1.3版本框架包. 其次,取出ThinkPHP3.1.3包中的核心部分,部署你的服务器项目下. ...

  3. 01背包java实现(入门到精通)

    一.什么是01背包 01背包是在M件物品取出若干件放在空间为W的背包里,每件物品的体积为W1,W2至Wn,与之相对应的价值为P1,P2至Pn.01背包是背包问题中最简单的问题.01背包的约束条件是给定 ...

  4. css常见布局方式

    CSS常见布局方式 以下总结一下CSS中常见的布局方式.本人才疏学浅,如有错误,请留言指出. 如需转载,请注明出处:CSS常见布局方式 目录: 使用BFC隐藏属性 float + margin abs ...

  5. handlebar JS模板使用笔记

    直接上代码: (定义模板) (编译注入) ***知识点*** //数据必须为Json数据(强调:jsonp数据不行,和json是两种数据,jsonp多了callback回调函数来包裹json数据) 遍 ...

  6. 使用VLC创建组播流

    vlc既是一个播放器,又可以成为一个流媒体服务器.最近需要做udp组播播放相关的东西,需要先在本地搭建一个udp组播服务器,因为机器上本来就装有vlc,所以就用它了. 第一步: 点击媒体->流 ...

  7. Ricequant-米筐金工-估值因子

    Ricequant米筐金工--因子分析 作者:戴宇.小湖 上一篇介绍了单因子检验是因子分析前重要的一个步骤,是构建因子库.建立因子模型的基础,这篇报告首先对常见估值因子进行初步的检验. 第一篇.估值因 ...

  8. linux 下的文件目录操作之遍历目录

    通过递归调用读取目录和文件信息去遍历整个目录: 示例代码: #include <unistd.h> #include <stdio.h> #include <dirent ...

  9. Kotlin——最详细的环境搭建

    众所周知,Kotlin出来已经有一段时间了.Kotlin有着众多优势,不管是用于Android开发中,还是Java开发,都能缩减很大的代码量,大大提高了工作效率.而小生本人也是才从忙碌的个工作中抽身出 ...

  10. (转)Nginx与tomcat组合的简单使用

    原文出自:http://www.cnblogs.com/naaoveGIS/ 1.背景 项目中瓦片资源越来越多,如果提高瓦片的访问效率是一个需要解决的问题.这里,我们考虑使用Nginx来代理静态资源进 ...