优化的意义
现阶段PC的性能绝大多数情况是过剩的,但移动端性能就参差不齐了,因此对移动端 H5 页面进行精细的性能优化是极其重要的。
移动端的WEB页面本身渲染性能差于Native的APP,尽管产品的功能,不关注性能优化,将极大的影响WEB页面的体验。
用户感知
当用户能够在1-2秒内打开H5页面,看到信息的展示,或者能够开始进行下一步的操作,用户会感觉速度还好,可以接受;而页面如果在2-5秒后才进入可用的状态,用户的耐心会逐渐丧失;而如果一个界面超过5秒甚至更久才能显示出来,这对用户来说基本是无法忍受的,也许有一部分用户会退出重新进入,但更多的用户会直接放弃使用。
优化方案
1、资源加载
1.1 首屏加载
当页面资源较多时,用户从点击开始加载页面,用户第一感知是什么时候「加载完成」?正常情况下,应该是在可见屏幕范围内,页面内容完全展示,如果在弱网状态下,会出现资源加载进度条,这样避免资源未加载完,展示出残缺不全的页面,影响用户体验,因此「首屏加载」时间是一个重要的优化点。
在加载时间较长的时候,务必要让用户明确感知到加载完成的提示,通常是在加载过程中显示Loading的进度条,加载完成的时候隐藏它。从心理上,这会让用户有一种“期待”感,而不至于太过枯燥。
对于一些重量级的移动WEB应用,例如「游戏H5」、「场景式H5」,开始前需要加载很多资源,为了让后面的游戏过程更为流畅,一个带百分比的进度条就显得格外重要。
1.2 按需加载
按需加载能够提升首屏加载速度,但尽可能避免对低性能的移动设备的影响,按需加载可能带来更多的重绘,从而降低了渲染性能,出现卡顿死机现象。
1.3 资源懒加载 Lazyload
懒加载已经有很多成熟方案,PC端常用的优化点,同样适用于移动端。
- 用户主动触发时的交互内容(如:滚屏加载¹,一种常见的无刷新动态加载数据的方案)
- 首屏未使用到的资源
①.滚屏加载是一种常见的无刷新动态加载数据的方案,通常用在列表形式数据展示中。一方面,数据不是通过翻页进行加载,这样就避免了再一次请求和渲染整个页面;另一方面,数据显示的数量是受限的,例如第一次只请求了10条数据,也就只需要渲染这10条数据,下拉滚屏的时候,再去获得下面10条数据。
1.4 资源预加载 Preload
预先加载利用浏览器空闲时间请求将来要使用的资源,以便用户访问下一页面时更快地响应。
- 无条件预先加载:页面加载完成(load)后,马上获取其他资源。以 google.com 为例,首页加载完成后会立即下载一个 Sprite 图片,此图首页不需要,但是搜索结果页要用到。
- 有条件预先加载:根据用户行为预判用户去向,预载相关资源。以 google.com 为例,开始输入时会有相关关键词提示,产生额外资源加载。
- 「被」预先加载:页面即将上线新版前预先加载新版内容。网站改版后由于缓存、使用习惯等原因,会有旧版的网站更快更流畅的反馈。 为缓解这一问题,在新版上线之前,旧版可以利用空闲提前加载一些新版的资源缓存到客户端,以便新版正式上线后更快的载入。如「6.18」、「双十一」这类重大促销节之前,可以预先下载一些相关资源到客户端(浏览器、App 等),有效利用浏览器缓存和本地存储,降低活动当日请求压力,提高用户体验。
1.5 第三方资源异步加载
第三方资源有的时候不可控,例如埋点统计、地图显示、分享组件等,诸如此类第三方资源使用时需慎重,充分考察它们对于性能的影响,使用异步加载的方式进行,防止第三方资源挂掉影响到页面本身的功能。
2、减少HTTP请求数
Web 前端页面大量的响应时间花在下载图片、样式、脚本等资源上。而浏览器对每个域名的连接数是有限制的(参考:浏览器允许的并发请求资源数是什么意思?),减少请求次数是缩短响应时间的关键。
图片资源
- CSS Sprite¹
- base64:URL (内联资源,有兼容问题,不会被缓存)²
- SVG Sprite(未来趋势,国外大量网站在使用)
- Icon Font
- 对于少量图片压缩,推荐用腾讯智图
- 利用CSS3技术绘制简单icon
Javascript、CSS、HTML等
- 合并文件(Node.js工具流Webpark)
- 并压缩(Node.js工具流Gulp)
- 安排JS/CSS放到合理的部分
- 尽量使用CSS3动画代替JS/Flash动画
- 避免空标签,避免空src
- 避免内联样式
- touchstart,touchend,click分情况使用
- 使用<!DOCTYPE html>
- 使用UTF-8字符集
- 使用引入CSS ,避免使用@import
- 尽量使用外链JS和CSS资源
- 尽量将脚本放入页面底部
- 不要去兼容IE6了,好吗?
服务端、域名等部署
- 服务端启用Gzip技术
- CDN自动合并技术
- 利用CDN加速静态资源
- 资源分域存放,分域请求(如:img.360buyimg.com存放图片)
- 设置合理资源缓存时间
- 减少Cookie
- 配置Etag文件版本标识,高效利用缓存,避免重复下载
- 服务端接口合并
- 避免与服务端接口不必要的数据传输
- 合理选用GET、POST请求方式³
①.通过简洁的设计减少页面所需资源,进而减少 HTTP 请求,比如我的博客就很简洁,但是在商业公司开发项目往往并不能做到简洁,为了提升用户感知和视觉体验,往往会加载很多点缀的小图片,这时候CSS Sprite就发挥作用了。
②.某些图片特立独行,它们很尺寸很小,在网站中很少更新,且在网站群大量使用,这个时候 base64:URL 就发挥大作用了。
③.根据 HTTP 规范,GET 用于获取数据,POST 则用于向服务器发送数据,所以 Ajax 请求数据时使用 GET 更符合规范(GET 和 POST 对比)。
3、减少DNS查询
确认 URL 以后,浏览器首先要查询域名(hostname)对应服务器的 IP 地址,一般需要耗费 20-120 毫秒 时间,浏览器缓存 –> 本地Hosts查询 –> DNS服务器。DNS 查询完成之前,浏览器无法识别服务器IP,因此不下载任何数据。
基于性能考虑,ISP运营商、局域网路由、操作系统、客户端(浏览器)均会有相应的DNS缓存机制。
- IE 缓存 30 分钟,可以通过注册表中 DnsCacheTimeout 项设置;
- Firefox 混存 1 分钟,通过 network.dnsCacheExpiration 配置;
- Chrome - > 设置 - > 选项 - > 高级选项 - > 去勾 “用预提取 DNS 提高网页载入速度”
4、避免出现资源访问失败
开发过程中,发现很多开发者没有设置图标icon,然而服务端根目录也没有存放默认的Favicon.ico,从而导致请求404出现,通常我们在APP里的webview打开,不会去加载这个Favicon.ico,但是很多页面能够分享出去,如果用户在浏览器打开,就会调取失败,一般尽量保证该图标默认存在,文件尽可能的小,并设置一个较长的缓存过期时间。
另外应及时清理过期导致出现请求失败的资源。