决定优化方向
首先打开 Inspect - Network 查看请求情况,从图片可以看出,DOMContentLoaded 时间为 2.67s,Load 时间为 3.45s,资源交换为 2.4MB。
优化方向主要在以下几个方面:
DNS 解析时间比较长资源加载量大首页并没用到高德地图,高德地图的请求阻塞了后续资源的加载流式请求的加载顺序阻塞了后续请求的发起图片的格式未针对浏览器进行优化,体积比较大,小型图片可以使用 svg 替换 png页面接口调用比较晚,时机不对js_ticket 等业务无关的请求可以提前轮播图片不用一次性全部加载请求阿里云 OSS 上的静态文件不添加时间戳参数(每次回源速度变慢)
解决方案
提早解析 DNS
解决第一个问题(DNS 解析时间比较长)。
<link rel="dns-prefetch" href="//oss-">
dns-prefetch通过指定具体的 URL 来告知客户端未来会用到相关的资源,这样浏览器可以尽早的解析 DNSpreconnect不光会解析 DNS,还会建立 TCP 握手连接和 TLS 协议prefetch支持预拉取图片、脚本或者任何可以被浏览器缓存的资源。
Nuxt.js 在 nuxt.config.js 文件中配置,关于这个属性的介绍可以查看 MDN 文档。
HTTP/2
改善第二个问题(资源加载量大)。
HTTP/2 也被称为 HTTP 2.0,相对于 HTTP 1.1 的新增多路复用、压缩 HTTP 头、划分请求优先级、服务端推送等特性,解决了在 HTTP 1.1 中一直存在的问题,优化了请求性能,同时兼容了 HTTP 1.1 的语义。目前,Chrome、 IE11、Safari 和 Firefox 等浏览器已经支持 HTTP/2 协议。
HTTP/2 的优势:
内容安全:浏览器端 HTTP/2 必须基于 HTTPS,具有安全特性。使用 HTTP/2 特性可以避免单纯使用 HTTPS 引起的性能下降问题。
多路复用(MultiPlexing):通过该功能,在一条连接上,您的浏览器可以同时发起无数个请求,并且响应可以同时返回。另外,多路复用中支持了流的优先级(Stream dependencies)设置,允许客户端告知服务器最优资源,可以优先传输。
Header 压缩(Header compression):HTTP 请求头带有大量信息,而且每次都要重复发送。HTTP/2 采用 HPACK 格式进行压缩传输,通讯双方各自缓存一份头域索引表,相同的消息头只发送索引号,从而提高效率和速度。
服务端推送(Server push):同 SPDY 一样,HTTP/2 也具有客户端推送功能。目前,大多数网站已经启用 HTTP/2,如淘宝。使用浏览器 Chrome 登录控制台,您可以查看是否启用 HTTP/2。
kong 如何开启 http2
kong 是一个基于 OpenResty 的网关层应用。较新版本在绑定证书 SNI 后访问 https 会自动开启 http2。
如果你使用的较低版本的 kong,你可以遵循文档进行开启,主要流程有以下两个方面:
如果是 docker 部署,在启动容器的时候根据 kong.conf.default 添加变量 "KONG_PROXY_LISTEN= ... 0.0.0.0:8443 http2 ..."如果非 docker 部署,kong.conf 文件中 proxy_listen 添加 http2 指令
高德地图阻塞问题
原工程中在一个子页面中使用到了高德地图作展示,引入 SDK 的方式为在 nuxt.config.js 中 head 部分加载。总所周知在 head 部分加载 js 文件会导致的问题。
高德 SDK 的缓存策略是Cache-Control: no-store,浏览器将无法使用缓存数据,而据测试高德 SDK 请求时间平均高于 500ms。
解决方案:由于高德 SDK 只有 AMD 方式加载的模块和类 JSONP Callback 这两种异步加载方式,所以需要自行处理 SDK 加载。
伪代码示例:
const loadScript = () => {return new Promise((resolve, reject) => {const script = document.createElement("script");script.src = src;script.onload = () => {if (autoremove) {script.onload = script.onerror = null;document.head.removeChild(script);}resolve();};script.onerror = reject;document.head.appendChild(script);});};
阻塞后续请求
Middleware 流式请求的加载顺序阻塞了后续请求的发起,项目当前 Nuxt.js 中间件执行的顺序为了保证每个中间件执行成功,每个中间件使用的为顺序同步加载的方式(一个执行成功了再请求下一个)。
解决方案:将多个没有依赖关系的中间件合并执行。
图片优化
由于项目历史悠远,图片的格式未针对浏览器进行优化,体积比较大,大部分矢量图片替换成 svg ,体积可以减少很多,而且针对不同设备环境,不会出现模糊锯齿等问题。
而对于 UGC 内容图片,可以使用FEMessage/v-img: Use webp and lazyload images进行优化,具体的方式参照组件文档即可。
请求执行时机问题
由于某历史原因,首屏页面的接口在 mounted 周期执行,review 整个逻辑后,改为 created 中执行即可项目首屏一般会有一些每日 Tips 之类的接口请求,由于此类请求每天只会展示一次,可结合 Cookie 的 Expires 机制,在每天请求过后设置相应的 Cookie,于当日 24 点过期。即可减少一次请求由于调用微信公众号 SDK 需要提前进行签名,而且使用 hash 路由模式下仅需签名一次,所以可以将签名过程提前到页面加载后的第一个环节中,如果能实现 Server Side Render 则更佳阿里云 OSS 配置文件每次回源问题
项目中有许多 JSON 静态配置文件是储存在 OSS 中的,最初封装 Axios 请求时,为了获取最新结果(不使用缓存数据),在 Axios onRequest 中为每个请求都添加了时间戳参数。
这种方案虽然保证了每次请求的结果时效性,但对于不常变化的 OSS 文件带来了每次回源的后果,具体表现为每次请求的耗时都超过 100ms。
改进方案原想针对域名(or 中心)取消相应时间戳的添加,但经过测试发现,阿里云 OSS 对于修改过后的 JSON 文件没有相应的缓存机制,在微信环境中,部分机型可能永远无法获取最新结果,具体表现如下:
在第二次请求携带有 Last-Modified 等协商请求头的情况下,请求与返回的 Last-Modified 相同且 OSS 返回的状态码依然为 200 OK。
上述情况也有可能是项目所用的 JSON 文件太小,或者和网关层的相关实现有关
其他针对性调优
微信端不需要 FAVICON,项目中去除即可优化前后对比:
指标——优化前——优化后——提升比例
DOMContentLoaded Time——2.67s——500ms+——530%
Load Time——3.45s——749ms——460%
Resources Size——2.4MB——1.5MB——160%
从数据上看加载速度提升很夸张,个人猜测在测试机制上可能有较多的不足(没有进行严格的控制变量测试,没有进行多次测试去除干扰项等)。
免费试用
1.登陆 申请售前咨询,业务需求中加上推荐deepexi@zhihu将有专人联系开通。 2. 快速开通请拨打18026408340(运营专员),我们将为您提供咨询服务。 3. 最终解释权归滴普科技所有。
快速咨询
全场景数据智能引擎往期推荐
全渠道数字化营销平台 DEEPEXI DMmp.企业级研发效能利器 DEEPEXI DevOpsmp.数字化协同 | 企业级数字化协同平台DEEPEXI® DCPmp.企业级前端全链路开发服务平台:DEEPEXI Serverless(A20)mp.更多内容
全场景数据智能引擎DEEPEXI是滴普科技公司面向企业数字化领域打造的云原生智能平台,定位于企业数字化引擎,为企业提供数字化全栈解决方案。滴普科技致力于互联网/大数据/人工智能/物联网领先技术产品解决方案的研发和实施,是领先的全场景数据智能服务商。