京东微信购物首页性能优化实践

3,356 阅读15分钟

作者:龙朝忠

京东微信购物首页(以下简称微信首页)曾经作为微信购物一级入口(目前替换为京喜小程序)一直对性能有着极高的要求,本文将介绍微信首页的一些优化经验。

一般来说产品是按以下方式进行迭代的,我认为循环的起点应该是「收集用户反馈」,我们对页面的优化依据和目标一个重要来源就是用户的反馈,因此说网页优化我们先从网页监控开始聊起。

京东监控系统简介

京东前端监控涉及的系统主要有两个:测速系统和智能监控平台。

测速系统

网页将各个关键节点的测速信息(时间戳)上传给系统,系统收集信息后对每个节点按省份、时间、网络类型、客户端类型等多个维度进行统计,并提供可视化分析结果,可以很方便的监控网页的加载情况。

智能监控平台

网页按照约定格式上报信息给系统,系统收集信息后按照预设的分析模式统计分析结果,若分析结果不符合预期还提供给告警功能。

我们在微信首页 CSS 加载完成、HTML 加载完成、JS 加载完成、首屏图片加载完成、第一张图片加载完成等关键节点插入测速点,并根据业务特点对关键内容上报智能监控平台,如查询首屏 DOM 节点是否存在上报首屏可用率、检测重要接口返回信息上报接口可用率。这样我们就能对微信首页的运行健康情况有一个比较全面的了解。

微信首页监控的两个阶段

第一阶段:主要关注首屏内容的加载优化( 2014 ~ 2019.5 )

这个阶段我们我们关注网页的加载速度,我们选取首屏图片加载完成时间作为核心监控点,重点关注 CSS 加载完成时间、HTML 加载完成时间、JS 加载完成时间、第一张图片加载完成时间。

第一阶段我们的目标是首屏图片加载完成时间控制在 1000ms 以内,其他时间越短越好。为达到这个目的,我们采取了一下措施。

1、首屏直出

首屏直出,也就是服务端渲染( SSR ),微信首页使用的是一个高效的 C++ 模板- CS 模板生成微信首页首屏内容。

以上是服务端渲染( SSR )和客户端渲染( CSR )在浏览器中的呈现区别,根据我们测试系统检测采用首屏 SSR 后首屏图片加载完成时间减少了 1200ms 左右,而且体验更好了。

2、关键渲染路径优化

关键渲染路径( Critical Render Path )简称 CRP ,是指一系列在首屏渲染中必须发生事件,优化关键渲染路径就是优先显示与当前用户操作有关的内容。

这是一个不太「精确」的概念,主要是关键渲染的规定,这和业务息息相关。关键渲染通常来说是指首屏渲染(用户第一眼可见区域)、页面的核心内容部分(这个也有点抽象)。

关键渲染路径的三个属性
  • 关键资源:可能阻止网页首次渲染的资源。划重点:阻止网页首页渲染。
  • 关键路劲长度:获取所有关键资源所需的往返次数或总时间。就是获取所有关键资源要请求多少次。
  • 关键字节:实现网页首次渲染所需的总字节数,它是所有关键资源传送文件大小的总和。
阻止网页首页渲染的资源

根据浏览器工作原理,首先浏览器是构建内 DOM 树和 CSSOM 树,然后将 DOM 树和 CSSOM 树合成「渲染树」,通过渲染树计算出布局信息然后渲染到屏幕上。

因此从渲染流程上来说,HTML 和 CSS 肯定是阻止网页首页渲染的资源,因为没有它们就不能构建出渲染树。 JavaScript 因为可能修改 DOM 或 CSSOM ,因此默认情况下浏览器在解析到 script 标签时会停止 DOM 树的构建,等 JavaScript 执行完再从 script 标签位置重新开始构建 DOM ,所以说 JavaScript 也是阻止网页首页渲染的资源。

根据关键渲染路径理论,我们可以从三个方面去优化网页:

  • 尽量减少网页首次渲染的资源
  • 减少关键路径长度,减少请求次数
  • 减少关键资源大小
2.1、尽量减少网页首次渲染的资源——拆分首屏和非首屏

拆分首屏和非首屏目的是划分出关键资源,我们定义除底部 tab 以上的的部分为首屏内容,这部分内容用户会最先看到,后面的优化措施就是尽量让首屏内容尽快展示。

对于非首屏内容采取延迟加载的方式处理。JS、CSS 异步加载 ,图片资源懒加载(快进入可视区域时加载)。

2.2、减少关键路径长度,减少请求次数

关键渲染路径长度是指获取关键资源网络请求次数

对于这块的优化,我们采取了一下措施:

  • 首屏样式和 JS 内联
  • 合并 JS 文件到一个 JS
  • 首屏 ICON 图片内联处理
  • 底部导航图标合成雪碧图
2.3、减少关键资源大小

对于首屏资源我们按类别分别作了一下优化处理。

对于 HTML,我们使用 html-minifier 工具精简HTML内容,去除不必要的空格和换行。

对于 JS,我们基于 webpack 对其进行 Treeshaking ,使用 webpack 对 JS 进行 treeshaking 依赖 ES2015(ES6) 模块系统中的静态结构特性,因此这部分的优化需要对 JS 进行 ES6 改造。

对于 CSS,开发过程中经常出现某次活动的样式在活动下线后忘记去掉,到最后不敢轻易去掉,造成不少无用样式存在。打包的时候我们使用 purifyCSS 对这种样式进行删除。改工具的实现原理可以开阔为:将 CSS 选择器名称切割成一个个单词,然后在所有可能用到的文件中查找这些单词,若单词在没有出现在任何地方说明该 CSS 选择器对应的样式没有用到,可以删除。

微信首页由于历史的积累,存在不少无用样式,使用 purifyCSS 工具处理后能节省 58KB 的关键资源大小。

对于 JSON 文件 ,首页内容大都需要运营配置,因此存在大量 JSON 数据,经过长年的积累对性能的消耗已不容忽视,如下面的一个配置的解析就占用了 200ms。这块我们一是推动推动运营删除过期数据,二是推动优化 JSON 数据接口,接口智能删除过期数据。

3.图片的优化
3.1、使用 WEBP 和 DPG 格式代替 PNG 和 JPG。

我们在客户端检测当前环境是否支持 WEBP 和 DPG,并提供统一的转换函数,服务端也提供了相同的功能。

根据我们实验对比发现:

1、DPG 格式和 WEBP 格式均有明显的压缩效果,压缩比例平均在60%以下;

2、DPG 压缩比 WEBP 压缩的效果稍微更好一些;

3、DPG + WEBP 双压缩比单种格式压缩有更明显的提升,达到 30%。

3.2、图片无损压缩

这块包含两方面的措施,一是我们在使用工具发布微信首页时,对页面直接依赖的图片做无损压缩,这是后图片大都是设计师给的切图,切图存在大量无用的信息,这时候无损压缩一半能节省一半的大小。

另一方面是借助京东图片服务压缩图片,我们需要按图片服务要求格式访问图片即可获得压缩处理后的图片。

3.3 使用MP4代替GIF

根据我们测试对比,绝大情况下 MP4 的大小要比 GIF 小很多

这张图 GIF 大小为 125KB 转成 MP4 后变为 86KB ,减少了 31.2% 。

这张图 GIF 大小为 200KB 转成 MP4 后变为 90KB ,减少了 55% 。

4.资源预加载
4.1、Preload

Preload 是一个新的控制特定资源如何被加载的新的 Web 标准,这是已经在 2016 年 1 月废弃的 subresource prefetch 的升级版。一般来说,最好使用 preload 来加载你最重要的资源,比如图像,CSS ,JavaScript 和字体文件。这不要与浏览器预加载混淆,浏览器预加载只预先加载在HTML中声明的资源。Preload 指令事实上克服了这个限制并且允许预加载在 CSS 和 JavaScript 中定义的资源,并允许决定何时应用每个资源。

我们使用 Preload 加载微信首页头部 banner 第一张图和头部氛围图,这样能让用户更早看到完整的首屏内容。

4.2 Preconnect

Preconnect 是 HTTP 请求正式发给服务器前预先执行一些操作,这包括 DNS 解析,TLS 协商,TCP 握手,这消除了往返延迟并为用户节省了时间。我们对页面中常用域名做了 Preconnect 。

4.3 DNS prefetch/ Link-prefetch/Prerending

DNS prefetching 允许浏览器在用户浏览页面时在后台运行 DNS 的解析。如此一来,DNS 的解析在用户点击一个链接时已经完成,所以可以减少延迟。可以在一个 link 标签的属性中添加 rel="dns-prefetch" 来对指定的 URL 进行 DNS prefetching。

Link prefetching 假设用户将请求指定的 url,浏览器在空闲的时候获取资源并将他们存储在缓存中。

Prerendering 和 prefetching 非常相似,它们都优化了可能导航到的下一页上的资源的加载,区别是 prerendering 在后台渲染了整个页面,整个页面所有的资源。

对当前页面性能无提升,但是若浏览器支持,对跳转到的下一页意义很大。

第二阶段:以 RAIL 模型为基础的多维度优化( 2019.5 ~ now )

一直以来,我们都用「页面首屏图片加载时间」这个指标来作为优化我们性能的关键 KPI。但是此指标对于「页面白屏时间很长」、「进度条加载慢」、「搜索框、轮播 banner、底部导航三个模块出来比较慢」几个体验问题,是无法衡量的。即使我们把「页面首屏图片加载时间」这个数据优化的很小,也并不意味着页面的性能和体验很好。这说明拿这个来衡量页面性能远远不够,我们需要更多维度的性能指标来衡量页面的性能。另外,「页面首屏图片加载时间」是一个复合动作后的数据结果,包含了 css/js 加载和解析,以及图片的加载和渲染等综合情况,并不能很好的指导页面做性能优化。再者,这个指标并不是一个标准指标,跟开发同学具体的埋点很有关系,有些页面还很不好埋点(比如有些内容新人才可见,怎么算首屏)。综上来说,我们需要有更多维度的、更标准的性能指标来描述页面的性能,并指导页面做性能优化。

我们采用 Google 的 RAIL 模型,此模型关注 Web 应用生命周期的四个方面:响应( Response ,响应时间不超过 100ms ),动画( Animation,10ms 完成一帧),空闲( Idle,空闲时间越多越好),加载( Load,1000ms 内完成加载),并提出以用户为中心的性能指标。

RAIL 模型的愿景
  • 网页性能优化要以用户为中心;最终目标不是让您的网站在任何特定设备上都能运行很快,而是使用户满意。
  • 网页应该立即响应用户;在 100 毫秒以内确认用户输入。
  • 网页应该在设置动画或滚动时,在 10 毫秒以内生成帧。
  • 网页应该最大程度增加主线程的空闲时间。
  • 网页应该持续吸引用户;在 1000 毫秒以内呈现交互内容。
RAIL 模型对应的四个评估维度
  • Response:页面响应用户的操作应该 100ms 内
  • Animation:对于页面中的动画,应该再 10ms 内生成一帧
  • Idle:要实现小于 100 毫秒的响应,应用必须在每 50 毫秒内将控制返回给主线程
  • Load:要求您的网页在 1000ms 内呈现关键路径内容给用户
新性能模型下监控侧重点

当我们采用以用户为中心的性能模型时,我们肯定也需要采用以用户为中心的性能指标。

1、首次绘制时间(FP): FP 标记浏览器渲染任何在视觉上不同于导航前屏幕内容之内容的时间点

2、首次内容绘制时间(FCP): FCP 标记的是浏览器渲染来自 DOM 第一位内容的时间点,该内容可能是文本、图像、SVG 甚至 canvas 元素

4、首次有效绘制(FMP):这是一个「模糊」的概念,是指页面的主要元素开始绘制的时间

5、可交互时间(TTI): 用于标记应用已进行视觉渲染并能可靠响应用户输入的时间点。

6、Long Tasks 监控:根据实测,使用支持最好的 Chrome 实验,获得的监控结果也不太有用,因此 Long Task 监控展示作罢。

第二阶段的性能优化

第二阶段的性能优化基于第一阶段的基础上,为了能达到 RAIL 模型要求,我们进一步做了一下事情。

1、进一步深化关键渲染路径的优化

我们站在用户的角度,结合京东微信购物首页流量转化情况,分析认为首页除了首屏广告 banner,搜索框和底部导航作为用户使用频率最高的几个模块应该提前渲染。并以首屏广告 banner 作为首次有效绘制。

对于搜索框,之前需要加载 3 个 JS 请求和 1 个 CSS 请求才能渲染出来,致使搜索框的渲染严重滞后。我们把之前通过 JS 渲染的 DOM 直接以页面片形式引入,并将 CSS 样式内联,这样搜索框能在首屏加载时就显示出来,然后我们将 3 个 JS 文件合并成一个,这样就加快了搜索框的初始化。

对于底部导航依赖了一个独立的 CSS 文件,而且在很靠下的位置,我们把底部导航的代码提前到搜索框的下面,并将样式内联。

2、动画优化

动画是造成页面卡顿的重要元凶之一,尤其是是用 setInterval 实现的动画,容易造成丢帧现象。因此我们用 requestAnimationFarme 代替 setInterval ,解决了部分机型动画卡顿问题 。

3、滚动优化

当直接监听页面滚动时间时,由于滚动事件触发频率很高,即使一个简单的 handler 函数也会造成大量的开销。因此我们对滚动事件做了节流,只允许一个函数在 X 毫秒内执行一次,只有当上一次函数执行后过了你规定的时间间隔,才能进行下一次该函数的调用。

4、图片懒加载优化

为了实现图片 DOM 渲染时不加载,等到快进入可视区域时加载,我们需要不听的观察图片是否进入了可视区域。之前我们做法是开启定时任务,无限循环查询 img 标签是否在可视区,很容易生成 Long Task,造成页面响应迟钝。

使用最新的 IntersectionObserver 接口代替定时任务,将监控img是否可见的任务交给浏览器,能显著提高效率。

结束语

前端技术日新月异,网页的优化也是如此。如经典的雅虎军规,许多规则到现在仍然具有重要的指导意义,我们在日常的开发中也仍在严格遵守着,但是有一些则该谨慎看待。如进入 HTTP2 时代后,资源的合并就失去了意义,甚至从缓存角度来看会起相反的作用。我们在微信首页所做的这些优化措施可能对你的页面并不适用,但希望能给你一些启迪。


如果你觉得这篇内容对你有价值,请点赞,并关注我们的官网和我们的微信公众号(WecTeam),每周都有优质文章推送:

WecTeam