H5页面性能优化


sidebarDepth: 2
collapsable: true

h5页面性能优化

该部分内容主要整理了h5性能优化方案及常用工具的使用

优化方案

1、资源加载

1. 首屏加载

 

  • 即在可见的屏幕范围内,内容展现完全,loading进度条消失

2. 按需加载

  • 首先要明确,按需加载虽然能提升首屏加载的速度,但是可能带来更多的界面重绘,影响渲染性能,因此要评估具体的业务场景再做决定。 比如页面中使用到的图片,如果对应的视图部分没有显示出来,先不加载,等对应视图显示出来后再加载。

    Eg: 下面展示一个按需加载图片的逻辑

        // 页面加载完成时先调用一下,首屏内的图片。
        loadImg()
        document.addEventListener('scroll', function (e) {
        // 跟着滚动,继续加载剩下的图片
          loadImg()
        })
        function loadImg () {
        // slice可以将类数组转化成数组对象
          [].slice.call(document.querySelectorAll('[data-src]')).forEach(function (item) {
            // 判断元素是否已经进入视野
            if (item.getBoundingClientRect().y <= innerHeight) {
              // 设置src
              item.src = item.getAttribute('data-src')
              // 删除data-src属性,可以减少querySelectorAll的查询次数
              item.removeAttribute('data-src')
            }
          })
        }
        <img data-src="xxx"></img>
    

3. Lazyload

 

  • Lazyload,即延迟加载,这并不是一个新的技术,在PC时代也是非常常用的一种性能优化手段。这个方案的原则是让屏幕外,或者不影响整体效果显示的图片、背景等资源,在界面就绪之后再进行网络加载。

4. 滚屏加载

 

  • 滚屏加载是一种常见的无刷新动态加载数据的方案,通常用在列表形式数据展示中。

5. 第三方资源异步加载

 

  • 防止第三方资源的使用影响到页面本身的功能。

6. Loading进度条

 

  • 给用户视觉感受, 能够知道加载的进度

7. 避免30*/40*/50*的http status

8. Favicon.ico

 

  • 如果我们没有设置图标ico,则会加载默认的图标:域名目录下的favicon.ico。很多开发者没有注意到这一点,就会导致这个请求404或者500。保证图片存在,尽可能小一些, 并设置较长的缓存过期时间。

9. 资源离线

 

  • 使用“离线包”策略。一些固定的图片、js库等,被打包放入app中(或根据需要,在app启动的时候进行下载更新)。微应用中,网页代码里面加载网络资源的需求,就变成了直接加载本地文件,速度自然得到再一次巨大的提升。

10. 预加载

 

  • 通过统计用户的行为信息,预判用户下一步操作,并在操作之前提前加载项目的一部分内容。

11. 抽离第三方模块

 

  • 使用vendor配置,项目依赖的第三方模块将会被抽取出来生成一个新的bundle,这部分不会经常变动,因此可以有效地利用客户端缓存,在用户后续请求页面时会加快整体的渲染速度。

12. 本地数据持久化和更新机制(版本管理)

 

  • 对于一些时效性没有那么高的数据,可以考虑将接口数据缓存。而不是每次都要到服务端请求数据。弊端: 首次加载不可避免;服务端更新数据,客户端不能快速感知;数据更新后,需要重新渲染界面,界面刷新的性能消耗比正常情况更多,而且增加了程序的复杂度,容易出错。

2、图片的使用

1. 图片的使用格式选择

 

  • 格式选择。显示效果较好的图片格式中,有webp、jpg和png24/32这几种常见的图片格式。一般来说,webp的图片最小,但在iOS或者android4.0以下的系统中可能会有兼容性问题需要解决;Jpg是我们最常使用的方案,大小适中,解码速度快,兼容性问题也基本不存在,是我们在H5的应用中使用起来性价比最高的方案;Png24或png32,一般来说,显示效果肯定会比jpg更好,但是实际上人眼很难感知出来,所以在H5应用中要避免这种格式的大图片。对于少量的图片,推荐用智图或者tinypng等工具来帮助自己选择合适的大小、格式。图片中不要留白

  • 使用图片的替代(css3, svg, iconfont)

2. 小图片合并

 

  • 在html网页中,如果有多个小图片需要加载,不妨试试CSS Sprites方案,尤其是一些基本不变,大小差不多的操作类型图标。

3. 避免大小重设

 

  • 在html或者css中,如果有类似width: **px这样的代码,就要注意看一看了,如果说图片显示的效果是宽度100px,而下载的图片却是200px宽度,那这大小基本上就是所需要的4倍面积了,所以在H5应用中,使用图片的一个原则就是需要显示成多大,就下载多大的资源。

    智能PNG和JPEG压缩: https://tinypng.com/

    PNG压缩与格式转换工具: https://isparta.github.io/

4. 像素控制

 

  • 在H5应用中,图片的像素要严格控制,一般来说不建议宽度超过640px

5. 避免DataURL

 

  • h5下尽量避免使用dataUrl, 因为它的数据体积通常比二进制图片的格式大1/3,而且它不会被浏览器缓存,每次页面刷新都需要重新加载这部分数据。

3、域名/服务端部署

1. Gzip

 

  • 服务端要开启Gzip压缩。对用户请求的页面进行压缩处理,以达到节省网络带宽,提高网站速度的作用

  • Nginx如何开启GZIP功能

  • 相对apache 和 IIS nginx开启GZIP简单很多,只需要打开配置文件 nginx.conf找到gzip on 把前面的注释符号#去掉即可开启GZIP服务。然后配置GZIP即可。下面是一个相对优化不错的配置,DNSLA建议使用。

    Gzip on;
    
    gzip_min_length 1024;
    
    gzip_buffers   4  8k;
    
    gzip_types   text/plain application/x-javascript text/css  application/xml;
    

2. 资源缓存,长cache

 

  • 合理设置资源的过期时间,尤其对一些静态的不需要改变的资源,将其缓存过期时间设置得长一些。

3. 分域名部署(静态资源域名)

 

  • 将动态资源和静态资源放置在不同的域名下,例如图片,放在自己特定的域名下。这样的好处是,静态资源请求时,不会带上动态域名中所设置的cookie头信息,从而减少http请求的大小。

4. 减少Cookie

 

  • 尽量减少Cookie头信息的大小,因为这部分数据使用的是上行流量,上行带宽更小,所以传输速度更慢,因此要尽量精简其大小

5. cdn加速

 

  • 部署CDN服务器,或者使用第三方的CDN加速服务,优化不同地域接入网站的带宽速度。

4、代码资源

1. Javascript, CSS合并

 

  • 尽量将所有的js和css合并,减少资源请求的次数。
  • 外联使用js, css:外联使用js和css,这样可以有效地利用缓存,避免html页面刷新后重新加载这部分代码。
  • 提取出公共部分,将可能多次使用的方法提取出来
  • 对于一些特定情况下才需要的js文件,使用动态创建script标签的方法引入

2. 压缩html, js, css

 

  • 压缩代码,尤其是js和css资源,压缩后的大小可以降低至原来的1/3以下,有效节约流量。

3. 资源的版本更新

 

  • 库js、css通常不会更新,但是我们的业务js和css可能会有更新,如果命中浏览器缓存,可能会让一些新的特性不能及时展现,甚至可能导致逻辑上的冲突。

  • 因此对于这些js、css的资源引入,最好用版本号或者更新时间来作为后缀,这样的话,后缀不变,命中缓存;后缀改变,浏览器自动更新最新的代码。

4. Css位置

 

  • CSS要放到html代码的开头的head标签结束前。如果网页是动态生成的,那么在head代码完成后可以强制输出(例如php的flush()操作),这样的话,浏览器就会更快地解析出来head中的内容,开始下载css文件资源。

5. js的位置

 

  • js的位置写在尾部, 使得js的加载不会影响初始页面的渲染

4、代码规范

1. 避免空src

 

  • 导致无效请求

2. 合理使用css

 

  • 正确使用Display属性 Display属性会影响页面的渲染,因此请合理使用
  • display:inline后不应该再使用width、height、margin、padding以及float
  • display:inline-block后不应该再使用float
  • display:block后不应该再使用vertical-align
  • display:table-*后不应该再使用margin或者float
  • 不滥用float
  • 不声明过多的font-size
  • 值为0时不需要单位
  • 标准化各种浏览器前缀
  • 避免让选择符看起来像是正则表达式。高级选择器不容易读懂,执行耗时也长
  • 尽量使用ID选择器
  • 尽量使用css3动画
  • 避免css表达式,可能会让页面多次执行计算,造成卡顿等性能问题
  • 避免空css规则, 降低css渲染计算的成本
  • 避免直接设置元素style, 直接设置style属性,一方面在html代码中不利于缓存,另一方面也不利于样式的复用,因此要避免,通过指定id或者class的方式,在css代码块中进行样式调整

3. js

 

  • 尽量使用for循环替代for in 循环, 因为它需要同时搜索对象的实例和原型属性
  • 用变量缓存需要的对象或者数组成员
  • 优化if-else, 把出现几率最多的条件放到首位,按出现几率的大小依次排列, 最小化找到分支之前所判断条件体的数量
  • 捕获异常与处理、上报, 网络环境、网速、代码等,很容易会出现一些问题,通过代码捕获或处理,可以不断优化代码,提高代码的健壮性
// vue中异常捕获 指定组件的渲染和观察期间未捕获错误的处理函数。这个处理函数被调用时,可获取错误信息和 Vue 实例。
Vue.config.errorHandler = function (err, vm, info) {
  // handle error
  // `info` 是 Vue 特定的错误信息,比如错误所在的生命周期钩子
  // 只在 2.2.0+ 可用
}
  • debounce处理时间频繁触发问题

     1. window对象的resize、scroll事件
     2. 拖拽时的mousemove事件
     3. 射击游戏中的mousedown、keydown事件
     4. 文字输入、自动完成的keyup事件
     等。。。
    
     以上这些场景往往会造成事件被频繁触发, 频繁执行DOM操作、资源加载等重复行为,导致UI停顿甚至浏览器崩溃。
     使用debounce可以处理这些场景,避免重复多次调用相同的操作,即函数调用频率的控制器。
    
  • throttle:一个连续操作中的处理,按照阀值时间间隔进行触发,从而实现节流

4. other suggestions,html和js 相关

 

  • 减少重绘和回流
  • 缓存dom选择和计算
  • 缓存列表.length
  • 尽量使用事件代理,避免批量绑定事件
  • 使用touchstart,touchend代替click
  • Html使用viewport
  • 减少dom节点
  • 合理使用requestAnimationFrame动画代替setTimeOut
  • 适当使用Canvas动画
  • TouchMove, Scroll事件会导致多次渲染
  • 不要使用强制浏览器重新计算布局的 JavaScript。将读取和写入功能分开,并首先执行读取
  • 不要使CSS 过于复杂。减少使用 CSS 并保持 CSS 选择器简洁
  • 尽可能地避免布局。选择根本不会触发布局的 CSS
  • 绘制比任何其他渲染活动花费的时间都要多。请留意绘制瓶颈

6、服务端接口

1. 接口合并

 

  • 如果页面需要请求两部分以上的数据接口,建议将其合并,否则会增加一次http请求。

2. 减少接口数据量

 

  • 有的时候,服务端会把一些无关紧要的数据返回回来,尤其是类似于更新时间、状态等信息,如果在客户端不影响内容的逻辑展示,不妨在接口返回的数据中直接去掉这些内容。

3. 缓存

 

  • 缓存接口数据,在一些数据新旧敏感性不高的场景下很有作用,在非首次加载数据时候优先使用上次请求来的缓存数据,可以让页面更加快速地渲染出来,而不用等待一个新的http请求结束之后再渲染。

4. cancelToken

 

  • 使用cancelToken, 将不需要的接口调用取消,减少不必要的带宽资源浪费。

7、 项目级优化

1. 项目代码打包后,每个组件对应一个js文件和一个css文件

 

  • 通过懒加载的方式, 按需引入所需资源,一定程度上减少了首屏加载的白屏时间。这种情况下,即使style标签中只有一些无用的css样式标签, 也会生成对应的css文件,增加无用的页面请求,因此应该避免使用无效css标签。

2. 生产环境打包设置 sourceMap: false,不生成sourceMap文件

 

  • 我们排查问题是通过本地代码代理到开发环境、测试环境或者后端同事的电脑上,直接定位问题的位置, 不需要sourceMap文件, 而且sourceMap文件比较大,不生成这些文件,即节省了打包时间,也减小了包的体积。

页面性能分析

1. lighthouse

使用lighthouse的三种方式

Chrome 开发者工具
命令行 (Node.js)
Chrome 扩展程序

  • 第一种方式使用方便,打开devtool,点击audit后点击generate report即可,但是可能会经常碰到 卡顿在 lighthouse is warming up这一步上。
  • 第二种方式 使用命令行, 全局安装lighthouse: npm install -g lighthouse即可,然后在终端输入: lighthouse url(想要测试的网址),eg: lighthouse https://www.baidu.com. 命令:lighthouse --help 可以查看可用的输入输出选项

lighthouse 最终默认生成html文件,报告中会给出相应的修复方案,根据生成的报告结果,可以分析页面的性能,并对不足之处作出修改。示例如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iHcrYRZH-1586738668395)(…/.vuepress/public/img/lighthouse.jpg)]

  参数,可选择:
  performance: 性能
  progress web app(pwa): 渐进式web应用
  Best Practices: 一般是一些最佳实践的建议
  Accessibility: 可访问性
  seo: 搜索引擎优化

2. 命令行方式

  • 控制台直接运行命令: window.performance.getEntries(),其中duration 参数返回的该事件的耗时

    浏览器获取网页时,会对网页中每一个对象(脚本文件、样式表、图片文件等等)发出一个HTTP请求。而通过window.performance.getEntries方法,则可以以数组形式,返回这些请求的时间统计信息,每个数组成员均是一个PerformanceResourceTiming对象!
    我们可以在控制台输入window.performance.getEntriesByType('paint') 来获取 First Paint (FP:文档中任意元素首次渲染时间)和 First Contentful Paint (FCP:也就是我们常说的 白屏时间 )
    如果希望查看组件的相关信息,可以设置Vue.config.performance=true;设置为 true 以在浏览器开发工具的性能/时间线面板中启用对组件初始化、编译、渲染和打补丁的性能追踪。只适用于开发模式和支持 performance.mark API 的浏览器上。
    

TTFB是“最初的网络请求被发起”到“从服务器接收到第一个字节”所花费的毫秒数。

3. coverage

使用coverage查看页面首次渲染加载资源的使用覆盖率,并根据分析结果,作出相应的调整,比如从未使用的代码,可以删除;不被立即执行的待使用懒加载。 示例如下图,红色为表示该部分代码未使用到, 绿色表示使用到

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cSOqSv7Y-1586738668399)(…/.vuepress/public/img/coverage.jpg)]

你可能感兴趣的:(经验总结)