Lianer

背景

随着业务的快速发展,业务系统越来越颗粒化。为了保证性能,往往会把首页抽离出来作为一个独立的系统,内页也根据业务拆分为多个系统,由各个团队负责维护。可能有的团队使用 Vue 作为基础框架,而有的团队使用 React,访问不同的系统都需要加载大量的静态资源文件,用户的感受就是“打开每个页面都很慢”,从用户体验来说是糟糕的。

因此,为了解决加载慢的问题,可以在用户的入口加入静态资源预加载的逻辑,将与当前页面有关联的静态资源都提前加载。

类似于浏览器的预加载机制,当用户在浏览器地址栏输入网址时,虽然你还没有回车,但是浏览器已经在后台默默的为你提前加载了,你就会感受到打开页面的速度非常快。

思路

要实现静态资源预加载需要注意几点:

一、适当预加载

只预加载与入口页有直接关联的静态资源,保证体验的同时,也需要考虑节省用户流量。

二、延迟预加载

iframe 中的静态资源会与入口页共享 HTTP 连接数,并且会阻塞入口页的 onload,体现为“Loading一直在转”,因此预加载静态资源不应该影响到入口页的加载,应当在 window.onload 之后再开始预加载逻辑。

三、排除业务代码

预加载的静态资源只应该包含核心插件,不要包含业务代码,业务代码往往对项目结构的依赖非常强,加载业务代码可能会抛出异常,一般来说虽然不会影响到系统稳定性,但是毕竟天天看着异常信息会很不舒服。

四、资源类型

需要支持的资源类型有 css 和 js 两种,图片往往是偏向业务的,并且图片不会阻塞网页渲染,因此不在预加载的考虑范围内。

五、兼容性

预加载有很简单的办法,就是使用 HTML5 prefetch 特性,但这个特性在 safari 上全军覆没,就是说不能在 iOS 中使用该特性。因此需要降级支持,采用传统的 link 和 script 标签来加载。

方案

  1. 在入口页 window.onload 事件之后,并延迟 2 秒,保证所有的异步任务都完成了;
  2. 动态创建 iframe,插入到 body 中,并设置为隐藏;
  3. 判断是否支持 HTML5 prefetch 特性,采用不同的方案加载静态资源;
  4. iframe 触发 onload 后销毁 iframe。

具体代码见 Github: https://github.com/lianer/preload-assets

结论

该方案应用于微医 APP 首页,将内容页的几个相关系统的静态资源进行了预加载,明显提升了首次访问的速度,包括:活动系统、微医严选、社区等。

其它

除了预加载静态资源,更可以做其它优化,比如:

  • 预解析 dns(避免滥用)
  • 基于 localStorage 的强制静态资源缓存