• home > webfront > SGML > html5 >

    再谈前端性能优化前端系列——移动页面性能优化

    Author:[email protected] Date:

    页面优化是个亘古不变的话题,之前写了很多此类文章,这篇文章做了些总结,更多的是一片技术指引散文,如果是转载,请访问原文,随时保持更新

    作为前端,应该都知道雅虎军规,而且google的chrome流量器pagespeed也能应付其中优化流程,具体可以查看:《前端性能优化--从 10 多秒到 1.05 秒》,《移动前端系列——移动页面性能优化》,大而全的《前端性能优化指南》,细分教程觉得没有必要写,本文只是一些总结性回顾。


    下面基于一个页面从开始到呈现完毕需要的四个阶段来讲谈谈优化过程

           移动前端系列——移动页面性能优化.

          而其中加载时优化的关键部分:

    移动前端系列——移动页面性能优化.

    文件优化

    加载方面的优化,首先是减少加载文件体积,这个优化效果最明显

    代码压缩

    • html+css压缩,在开启gzip的情况下,影响微乎其微。如果用户只限定国内,文件编码采用GBK(本人觉得没有没有必要)

    • js代码压缩, 代码混淆个人觉得没有必要,毕竟前端环境近乎透明

    • 图片压缩: 传统做法有png24转png8、jpg加大压缩比率。而现在需要根据user-agent匹配图片(高清图1x,2x匹配,webp匹配等),具体规则如下:

      传统做法就是用adobe bridge或者ps批处理压缩图片,[email protected] [email protected]

      一般比如可以采用七牛或者腾讯智图,上传高清图片,让CDN自动去压缩。

      如果CDN没有相关环境,html里面还是xxx.jpg,nginx根据useragent判断转发 适配图片js+css 兼容性问题 ,为了节省加载体积,也可以根据客服端分发(虽然节省不了多少空间,但是代码洁癖使然)

      网上各种教程推荐用srcset、sizes和picture+source让浏览器去匹配,这种无疑增加了前端代码量,为什么让服务端做呢?

    • 减少图片请求:

      传统做法就是 sprint拼接(雪碧图)——在http2.0下无必要。

      图标icon用font-icon替代,从UI上尽量扁平化,能用css3解决就用css3解决。

      小图片转base64(我不推荐这个,因为:

      1. 阻塞渲染进程,

      2. 缓存共享不好,

      3. DataURI要比简单的外链资源慢6倍,生成的代码文件相对图片文件体积没有减少反而增大,而且浏览器在对这种base64解码过程中需要消耗内存和cpu,这个在移动端坏处特别明显。

    2、给文件制定文件编码,具体参考《HTML字符编码解析是如何影响浏览器性能的

    网络层优化:

    开启DNS缓存、减少重定向

    移动前端系列——移动页面性能优化.

    这是一个同一网速下的测试结果,重定向之所以会比较慢,是因为它重复了域名查找,tcp链接,发送请求。

    这里需要,复习下nginx的 last 和 break VS permanent 和 redirect ,推荐阅读:《Nginx葵花宝典—草根站长Nginx运维百科全书

    至于如何开启DNS缓存,这个得一系列优化属性:

    • dns-prefetch:可以指定一个用于获取资源所需的源(origin),并提示浏览器应该尽可能早的解析。

    • preconnect:用于启动预链接,其中包含DNS查找,TCP握手,以及可选的TLS协议,允许浏览器减少潜在的建立连接的开销。

    • prerender:用于标识下一个导航可能需要的资源。浏览器会获取并执行,一旦将来请求该资源,浏览器可以提供更快的响应。浏览器将预加载目标页面相关的资源并执行来预处理HTML响应。

    • preload:通过一个现有元素(例如:img,script,link)声明资源会将获取与执行耦合在一起。然而应用可能只是想要先获取资源,当满足某些条件时再执行资源。

      Preload提供了预获取资源的能力,可以将获取资源的行为从资源执行中分离出来。因此,Preload可以构建自定义的资源加载与执行。例如,应用可以使用Preload进行CSS资源的预加载、并且同时具备:高优先级、不阻塞渲染等特性。然后应用程序在合适的时间使用CSS资源:

    • prefetch:用于标识下一个导航可能需要的资源。浏览器会获取该资源,一旦将来请求该资源,浏览器可以提供更快的响应。注:浏览器不会预处理、不会自动执行、不会将其应用于当前上下文。

    <link rel="dns-prefetch" href="//example.com">
    <link rel="preconnect" href="//example.com">
    <link rel="preconnect" href="//cdn.example.com" crossorigin>
    <link rel="prefetch" href="//example.com/next-page.html" as="html" crossorigin="use-credentials">
    <link rel="prefetch" href="/library.js" as="script">//as与crossorigin选项都是可选的。
    <link rel="prerender" href="//example.com/next-page.html">
    <link rel="preload" href="/styles/other.css" as="style">


    2、文件缓存,浏览器,利用manifest、serviceWork(pwd)、App本地包等,减少请求

    3、开启http2.0协议或者quick协议


    提升http并发

    1,采用多域名,增加浏览器对资源下载的并发:具体参考:《基于浏览器的并发请求资源优化网站

    2,采用http2,减少统一域名TLS开销。具体参考:《HTTP 2.0的那些事》,最新的quic协议生态支持弱,暂不推荐。

    改进缓存策略

    1,http 缓存策略,比如强制缓存,让浏览器用本地资源。推荐查看《浏览器缓存机制剖析》、《no-cache,max-age=0,nostore区别及304原理

    2,采用manifest缓存 《 html5离线缓存manifest详解

    3,如果是hybrid app,可以在终端缓存页面资源。通过manifest.json,热更新应用。

    4,PWA,可以尝试去做。

    渲染优化

    减少回流,具体参看:《chrome对页面重绘和回流以及优化进行优化》、《影响前端性能的本源——Reflow和Repaint

    动画优化

    推荐阅读《CSS Animation性能优化》《一篇文章说清浏览器解析和CSS(GPU)动画优化》

    repaint开销大的动画,踢出文档流

    用marginLeft, width ,height等属性改变dom时我们要注意减少影响的范围。基本原则就是,把动画元素用position:absolute踢出文档流,这样R&R就限制在了absolute元素的子节点。告诉浏览器,我这块结构跟其他的单独渲染,不要搅和全页面了。

    compositor layer 合成渲染层

    给动画元素使用translate3d属性或者简单加上translateZ属性,让浏览器以为这是要3d变换的元素,会让浏览器单独开合成层渲染你的动画效果。集中资源的好处是动画过程会更加平滑。

    下面这些因素都会导致新图层的创建:

    • 进行3D或者透视变换的CSS属性

    • 使用硬件加速视频解码的

    • 具有3D(WebGL)上下文或者硬件加速的2D上下文的

    • 组合型插件(即Flash)

    • 具有有CSS透明度动画或者使用动画式Webkit变换的元素

    有关于Composite方面的深入剖析,可以阅读《无线性能优化:Composite》一文。影响Web性能主要过程包括Layout、Paint和Composite。那么对于CSS Animation而言,只要是会触发Layout、Paint和Composite的CSS属性都会直接影响动画的性能。CSS中所有影响Layout、Paint和Composite的属性都可以通过CSS Triggers网站查阅。

    GPU加速其实是一直存在的,而如同translate3D这种hack只是为了让这个元素生成独立的 GraphicsLayer , 占用一部分内存,但同时也会在动画或者Repaint的时候不会影响到其他任何元素,对高刷新频率的东西,就应该分离出单独的一个 GraphicsLayer。


    RenderLayer 树,满足以下任意一点的就会生成独立一个 RenderLayer。

    • 页面的根节点的RenderObject

    • 有明确的CSS定位属性(relative,absolute或者transform)

    • 是透明的

    • 有CSS overflow、CSS alpha遮罩(alpha mash)或者CSS reflection

    • 有CSS 滤镜(fliter)

    • 3D环境或者2D加速环境的canvas元素对应的RenderObject

    • video元素对应的RenderObject

    每个RenderLayer 有多个 GraphicsLayer 存在

    • 有3D或者perspective transform的CSS属性的层

    • 使用加速视频解码的video元素的层

    • 3D或者加速2D环境下的canvas元素的层

    • 插件,比如flash(Layer is used for a composited plugin)

    • 对opacity和transform应用了CSS动画的层

    • 使用了加速CSS滤镜(filters)的层

    • 有合成层后代的层

    • 同合成层重叠,且在该合成层上面(z-index)渲染的层

    每个GraphicsLayer 生成一个 GraphicsContext, 就是一个位图,传送给GPU,由GPU合成放出。

    那么就是说,GraphicsLayer过少则每次repaint大整体的工作量巨大,而过多则repaint小碎块的次数过多。这种次数过多就称为 层数爆炸 ,为了防止这个爆炸 Blink 引擎做了一个特殊处理。

    不是所有属性动画消耗的性能都一样,其中消耗最低的是transform和opacity两个属性(当然还有会触发Composite的其他CSS属性),其次是Paint相关属性。所以在制作动画时,建议使用transform的translate替代margin或position中的top、right、bottom和left,同时使用transform中的scaleX或者scaleY来替代width和height。



    页面滚动时,需要避免不必要的渲染及长时间渲染。其中不必要的渲染包括:


    • position:fixed;fixed定位在滚动时会不停的进行渲染,特别是页面顶部有一个fixed,页面底部有个类似返回顶部的fixed,则在滚动时会对整个页面进行渲染,效率非常低。可以通过transform: translateZ(0)或者transform: translate3d(0,0,0)来解决

    • overflow:scroll。前面说了,而在滚动也会触发Repaint和Reflow。在调试过程中注意到一个有趣的现象,有时打开了页面并不会导致crash,但快速滑动的时候却会。由于crash是页面本身内存占比过高,只要优化了页面的内存占用,滑动自然也不会是很大的问题。无论你在什么时候滑动页面,页面滚动都是一个不断重新组合重新绘制的过程。所以减少渲染区域在滚动里就显得非常重要。

    • CSS伪类触发。有些CSS伪类在页面滚动时会不小心触发到。比如:hover效果有box-shadow、border-radius等比较耗时的CSS属性时,建议页面滚动时,先取消:hover效果,滚动停止后再加上:hover效果。这个可以通过在外层添加类名进行控制。但添加类名、删除类名也会改变元素时,浏览器就会要重新做一次计算和布局。所以千万要小心这种无意触发重新布局的操作,有的时候可能不是动画,但去付出的代价要比做一个动画更加昂贵。也就是说classname变化了,就一定会出现一次rendering计算,如果一定需要这么做,那可以使用 classlist 的方法。

    • touch事件的监听

    长时间渲染包括:

    • 复杂的CSS

    • Image Decodes:特别是图片的Image Decodes及Image Resize这两个过程在移动端是非常耗时的

    • Large Empty Layers: 大的空图层

    在CSS中除了开启3D加速能明显的让动画变得流畅之外,在CSS中提供了一个新的CSS特性:will-change。其主要作用就是提前告诉浏览器我这里将会进行一些变动,请分配资源(告诉浏览器要分配资源给我)。具体查看《关于CSS的will-change属性的介绍


    总的方向上,遵从以下三条:

    a) 尽量使用css3动画

    优点:不占用js主线程、可利用硬件加速、浏览器可对动画做优化

    缺点:不支持中间状态监听

    b) 适当使用canvas动画

    优点:可规避渲染树的计算渲染更快

    缺点:开发成本高、维护较麻烦

    c) 合理使用RAF(requestAnimationFrame)

    优点:能解决脚本问题引起的丢帧,卡顿问题、支持中间状态监听

    高频事件优化


    类似touchmove,scroll,resize这类的事件可导致多次渲染,对于这种事件可以通过以下手段进行优化:

    1. 节流,不明白可以推荐阅读《Debounce 和 Throttle 的原理及实现

    2. 使用requestAnimationFrame监听帧变化,使得在正确的时间进行渲染

    3. 增加响应变化的时间间隔,减少重绘次数。

    js事件优化

    在移动端请适当使用touchstart,touchend,touch等事件代替延迟比较大的click事件。Click之所以慢是因为mousedown导致的:

    移动前端系列——移动页面性能优化.

    最后,概括为一张大图(移动H5前端性能优化指南)

     移动H5前端性能优化指南


    参考文章:



    转载本站文章《再谈前端性能优化前端系列——移动页面性能优化》,
    请注明出处:https://www.zhoulujun.cn/html/webfront/SGML/html5/2016_0204_537.html