文章目录
  1. 1. 容器性能优化
    1. 1.1. 加速页面打开
      1. 1.1.1. 资源准备
      2. 1.1.2. 预加载
    2. 1.2. 加速页面切换
      1. 1.2.1. 容器预热
      2. 1.2.2. 容器切换
      3. 1.2.3. 客户端直出渲染
  2. 2. 结束语

前面我们讲了很多前端应用内部的性能优化,实际上除了前端自身,我们还可结合容纳 Web 页面本身的客户端一起做优化。

首先,本文中提到的容器,基本上都是指 Web 页面的宿主,比如浏览器、APP 客户端、小程序,它们提供了 WebView 环境来运行 Web 应用。

容器性能优化

由于 Web 应用本身只运行在 WebView 中,而 WebView 的能力又依赖于宿主容器,因此 Web 应用本身很多能力都比较局限。如果宿主容器能配合一起做一些优化,效果要远胜于我们自身做的很多优化效果。

从性能优化的角度来说,宿主容器主要能提供的能力包括:

  • 加速页面打开
  • 加速页面切换

加速页面打开

对前端项目来说,我们常常会对首屏打开做很多的优化,包括尽量减少首屏需要的代码、对首屏渲染的内容进行分片等等(参考《前端性能优化–归纳篇》)。

即使前端本身优化到极致,对于资源获取、请求数据等这些耗时占比较大的部分,还是存在的。但是如果容器能提供类似的能力,我们就可以将这部分的耗时做优化了,比如:

  • 提前下载并缓存 Web 相关资源,页面打开时直接获取缓存,比如 HTML/JavaScript/CSS
  • 提前获取和缓存页面渲染相关的请求资源,页面请求时直接返回,或是直接从缓存中获取
  • 提前启动 WebView 页面,并加载基础资源

资源准备

我们可以在客户端即将打开某个 WebView 页面之前,提前将该页面资源下载下来,由此加快 WebView 页面加载的速度。

由于资源请求本身也会消耗一定的资源,一般来说会在比较明确使用的场景下才会使用。也就是说用户很可能会点进去该 WebView 页面,基于这样的前提来做资源准备,比如列表页进入详情页,比如底部 TAB 进入的页面等等。

这些提前下载并临时缓存的资源,可以包括:

  • 页面加载资源,包括 HTML/CSS/JavaScript 等
  • 首屏页面内容的请求数据,比如分片数据的首片数据等

资源预下载要做的时候相对简单,需要注意的是下载后的资源的管理问题,在使用完毕或是不需要的情况下需要及时的清理,如果过多的缓存会占用用户机器的资源。

其实除了依赖客户端,前端本身也有相关的技术方案,比如说可以使用 PWA 提前请求和缓存页面需要的资源。

预加载

在需要的资源已经准备好的前提下,容器还可以提供预加载的能力,包括:

  • 容器预热:提前准备好 WebView 资源
  • 资源加载:将已下载的 Web 资源进行加载,比如基础的 HTML/CSS/JavaScript 等资源

举个例子,小程序中也有对资源预加载做处理。在小程序启动时,微信会为小程序展示一个固定的启动界面,界面内包含小程序的图标、名称和加载提示图标。此时,微信会在背后完成几项工作:下载小程序代码包、加载小程序代码包、初始化小程序首页。

小程序的启动过程也分了两个步骤:

  1. 页面预渲染。这是准备 WebView 页面的过程,由于小程序里是双线程的设计,因此渲染层和逻辑层都会分别进行初始化以及公共库的注入。逻辑层和渲染层是并行进行的,并不会相互依赖和阻塞。
  2. 小程序启动。当用户打开小程序后,小程序开始下载业务代码,同时会在本地创建基础 UI(内置组件)。准备完成后,就会开始注入业务代码,启动运行业务逻辑。

显然,小程序基础库和环境初始化相关的资源,都被提前内置在 APP 中了,并提前准备好相关的资源,使得用户打开小程序的时候,可以快速地加载页面。除此之外,小程序还提供了预加载的能力,业务方只需要配置提前拉取的资源,微信则可以在启动的过程中,提前将相关的资源拉取回来。

很多宿主预加载的方案也类似,比如对 WebView 页面做前置的资源下载和加载,当用户点击时尽快地给到用户体验。

加速页面切换

除了首次打开页面的加速,在页面切换时我们也可以做很多提速的事情。

容器预热

前面讲到,在打开小程序前,其实微信已经提前准备好了一个 WebView 层,由此减少小程序的加载耗时。

而当这个预备的 WebView 层被使用之后,一个新的 WebView 层同样地会被提前准备好。这样当开发者跳转到新页面时,就可以快速渲染页面了。这个过程也可以理解为容器的前置预热。

在这个例子中,小程序针对不同的页面使用了不同的 WebView 进行渲染,因此不管是首次打开,还是跳转/切换新页面,都会准备多一个 WebView 用来快速加载。

但多准备一个 WebView 本身也是对客户端的一种资源消耗,所以其实我们还可以考虑另外一种方案:容器切换。

容器切换

容器切换方案指当页面切换时复用同一个 WebView 资源,可以理解为前端单应用类似的方式在 APP 中做资源切换。

由于需要复用同一个 WebView,因此该方案对资源的管理要求较高,包括:

  • 对页面应用的生命周期管理完善,自顶向下实现初始化、更新和销毁的能力
  • 页面切换时,需要及时清理原有逻辑和资源,比如定时器、页面遗留的 UI 和事件监听等
  • 资源占用、内存泄露等问题,会随着 WebView 复用次数而积累

要达到不同页面和前端应用之间的资源复用,要求比直接准备一个新的 WebView 容器要高很多。即使是不同的页面,也需要有统一的生命周期管理,约定好页面的一些销毁行为,并能执行到每个模块和组件中。

但如果项目架构和设计做得好,效果要远胜于容器预热,因为在进行页面切换的时候,很多资源可以直接复用,比如:

  • 通用的框架库,比如使用了 Vue/React 等前端框架、Antd 等组件库,就可以免去获取和加载这些资源的耗时
  • 公共库的复用,项目中自行封装的一些工具库,也可以直接复用
  • 模块复用,通用的模块比如顶部栏、底部栏、工具栏、菜单栏等功能,可以在页面切换时选择性保留,直接省略这部分模块的加载和页面渲染

看到这里或许有些人会疑惑,如果是这样的话为什么不直接用单页面呢?要知道我们讨论的场景是客户端打开的场景,也就是说 WebView 页面的退出,大多数情况下是会先回到 APP 原生页面中。当用户进入到另外一个 WebView 页面时,才会重新打开 WebView,此时才考虑是用新预热的 WebView,还是直接复用刚才的 WebView。

总的来说,容器切换是一个设计要求高、副作用强、但优化效果好的方案。

客户端直出渲染

在有容器提供资源的基础上,我们还可以在 WebView 页面关闭前,对当前页面做截屏或是 HTML 保存处理。

在下一次用户进入到相同的页面中时,可以先使用上一次浏览的图片或是页面片段先预览,当页面加载完成后,再将预览部分移除。这种预加载(预览)的方案,由于是客户端提供的直出渲染能力,因此也被称为客户端直出渲染。

当然,相对于在页面关闭前保存,其实也可以直接实现直出渲染的能力,这样不管是否已经打开过某个页面,都可以通过容器预热时提前计算出直出渲染的内容,当页面打开时直接进行渲染。

这种方案有一个比较麻烦的地方:当缓存的页面内容发生变化时,需要及时更新直出渲染的内容。

因此,及时用户并不在页面内,也需要定期去获取最新的资源,并生成直出渲染的内容。当需要预渲染的页面多了,维护这些页面的实时性也需要消耗不少的资源,因此更适用于维护成本较低的页面。

结束语

其实,容器的作用不只是加速页面打开速度,由于结合了原生 APP 的能力,我们甚至可以给 WebView 提供完整的离线加载能力。比如在网络离线的情况下,通过提前将资源下载并缓存,用户依然可以正常访问 APP 里的页面。

当然,每一项技术方案都是有利有弊,容器提供了更优的能力,也需要消耗一定的资源,我们可以结合自己项目本身的情况来做取舍。

码生艰难,写文不易,给我家猪囤点猫粮了喵~

B站: 被删

查看Github有更多内容噢:https://github.com/godbasin
更欢迎来被删的前端游乐场边撸猫边学前端噢

如果你想要关注日常生活中的我,欢迎关注“牧羊的猪”公众号噢

作者:被删

出处:https://godbasin.github.io

本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

文章目录
  1. 1. 容器性能优化
    1. 1.1. 加速页面打开
      1. 1.1.1. 资源准备
      2. 1.1.2. 预加载
    2. 1.2. 加速页面切换
      1. 1.2.1. 容器预热
      2. 1.2.2. 容器切换
      3. 1.2.3. 客户端直出渲染
  2. 2. 结束语