钉钉小程序快照技术初窥

2021年11月24日 阅读数:13
这篇文章主要向大家介绍钉钉小程序快照技术初窥,主要内容包括基础应用、实用技巧、原理机制等方面,希望对大家有所帮助。

做者:孙然(煮虾)前端

对于小程序技术来讲,容器加载和前端异步渲染的过程当中当然不可避免的会有白屏或 loading 页的展现,短则一瞬间,长则须要数秒才能展现首屏。若是白屏时间长,将很是影响用户的体验。根据 Google 的统计,若是页面加载耗时超过了 3s,那么有 53% 的用户会选择直接退出该页面了。算法

为加速小程序首页的展现,支付宝和手淘运用了基于 HTML 的快照技术,主要思路都是缓存首页 HTML 供下次启动时与数据一块儿优先渲染以提早首屏展现的时间,适用于传统 WebView 渲染的小程序场景。这种基于 HTML 的快照技术可以极大缩短启动时的白屏时间,但首屏展现的速度仍是不够快,期间用户仍然会有可见的白屏感觉。而且快照展现的仍然是没法点击操做的页面,须要等待 JS 部分 ready 后才可点击交互。小程序

为了追求极致的体验效果,咱们提出了一种全新的小程序快照技术,目标是既作到完全消除白屏现象,同时也要可以响应用户交互。浏览器

核心思路

不一样于现有的基于 HTML 的快照技术,咱们提出了一种 native 的图像级别的快照技术,主要由如下三个步骤:缓存

  • 步骤1:在小程序启动后合适的时机将小程序首页保存为图片,咱们称之为快照
  • 步骤2:下次打开小程序时先展现上次保存的快照,再启动小程序
  • 步骤3:当小程序启动完后的合适时机,隐藏快照,展现出真实的小程序首页,并保存当前界面视图做为下次的快照(同步骤1)

效果

如今钉钉中的新建 DING 日程页面就运用了快照技术,先后效果对好比下:安全

before after

能够看出,经过快照技术,该页面实现了首屏秒开的效果,启动白屏的现象完全消失,页面的首屏渲染耗时从 1700ms 左右下降到了 300ms 如下。weex

下面我会对快照技术的几个关键考虑点进行详细介绍。网络

场景和时机

理想中的快照,应当是可以和首屏页面彻底重合,而且在快照隐藏时不会产生任何视觉变化的。那么生成快照的时机和运用快照的场景就直接决定了快照技术可以达到的优化效果。框架

什么页面适合用快照?

并非全部的小程序都适合使用快照技术来提高首屏体验。若是使用不当,快照可能还会成为体验的减分项。为达到最佳效果,通常首屏页面知足下面几个条件是比较适合使用快照的:异步

  • 首屏页面较为固定。若是首屏不固定,很难找到合适的快照时机来保证快照与下次的首屏重合
  • 首屏页面不含用户隐私数据。用户的隐私数据不该当被快照下来

何时生成快照?

若是快照的时机过早,快照可能展现的也是白屏或者未渲染完整的首页框架。

若是快照的时机过晚,可能用户已经对首屏有了交互(滚动、点击等),容易生成没法和首屏重合的快照。

因此须要根据不一样的首屏场景来肯定最佳的快照时机。通常咱们考虑快照的时机有:

  • 小程序首屏 Page 的 onReady 生命周期回调里。但此时页面极可能仍然没有渲染完成,能够考虑适当延时后进行快照
  • 小程序首屏的数据若是须要远程拉取,能够在远程获取到首屏数据后进行
  • 用户发生滚动时、点击等交互后再也不进行快照

何时隐藏快照?

咱们通常考虑在生成快照时去隐藏当前已经展现的快照。两者的顺序通常是在隐藏快照后当即生成快照,才能实现快照和真实页面的无缝衔接。

固然,也须要考虑小程序启动可能失败的场景。这里须要对展现快照的时间设置一个展现的上限,若是展现时间达到上限时小程序首屏仍然没有启动成功,那么快照将直接隐藏,以防形成首屏对用户可见但一直不响应的尴尬局面。

这里咱们在还隐藏快照时作了一个小小的视觉优化。考虑到在隐藏快照时,若是直接隐藏快照,一旦快照和真实页面稍有差异,在视觉上可能就会有闪烁的体感发生。

因此在隐藏快照时,咱们会作一个 200ms 的淡出动画,来缓解这种快照和真实页面差别致使的闪烁感。由于有时快照的时机可能会稍提早于首页网络数据加载成功、图片加载成功等这些异步事件成功的时机,致使快照比真实页面元素缺乏或者数据不许确,而淡出动画可以有效淡化这些差错形成的视觉异常感。下面的 demo 对比了这两种状况:

直出 淡出

可交互

因为快照和真实的首屏页面基本是相同的,从用户体感上用户会觉得首屏已经成功展示,也应该是个可交互的页面。因此单纯展现死的快照页面是远远不够的,作到可交互是咱们快照的重要能力

咱们的快照支持响应用户的点击行为,具体方法就是在用户点击快照时先暂存用户的点击事件,待快照隐藏时将这次事件分发到真实页面上去。

此过程当中若是用户有屡次点击事件,咱们只会响应最后一次点击事件。

从用户体感上来讲,可能用户会感受到这次点击的响应会比较慢,但不会让用户感知到它点击的是快照仍是真实首页。

若是是小程序启动较慢的场景,还能够考虑在用户点击后展现 loading:

为进一步提升快照层的可交互性,咱们甚至还能够容许开发者设定一些快照层的点击区域和简单操做,使用户在点击快照层的时候快速响应点击事件。例如钉钉的工做台就很是适合这种场景:工做台中的各个应用通常不会频繁变化,而且有很明确的分块区域:

能够配置好不一样的点击区域以及对应的 action (例如:跳转到其它页面/应用),形如:

[{
  area: {
    left: 100, 
    top: 100, 
    width: 100, 
    height: 100
  },
  action: {
    type: 'openLink', 
    params: { url: 'http://xxx' }
  }
}, ...]

这样用户在点击快照指定区域时就能直接实现跳转,而无需等待到小程序启动完成。

存储与安全

快照属于敏感数据,而且只保存在客户端本地不能进行上传,管理其存储必须格外当心,不然很容易酿成一块儿公关事件。

对于快照的存储,咱们考虑了如下几点:

加密存储

快照数据必须进行加密存储,这里加密方式用的是集团无线保镖里的加密方法。

隐私保护

快照里不能含有用户的隐私数据。也就是说,快照应当只含有一些 UI 元素或者无心义的默认数据,而不该该含有用户隐私数据。

不含用户隐私数据 含用户隐私数据

那么如何作到获取到不含用户隐私数据的首页快照呢?能够考虑在前端从网络、缓存中获取数据以前进行快照。但这样的快照一定是不完整的,会损失必定的体验,这也是咱们不推荐在有用户数据的首屏场景使用快照的缘由。

快照清理

快照被存储在客户端中,须要有存储上限。当快照数据达到必定量后,须要淘汰一些老的快照数据。\
其次,在小程序版本更新、用户登出切换用户时都应该考虑将现存的对应快照数据清理掉。

准确性

当快照上线后,咱们须要对快照的用户体验进行感知。最佳的体验是用户根本就没有感知到快照的存在,也就是快照和真实页面彻底重合;而若是快照和真实页面相差较大,则会让用户体验大大降低,这是咱们须要感知到的。

这里咱们主要关注快照的准确性指标,也就是快照和真实页面的类似(重合)程度。准确性越高,则说明快照与真实页面的过渡约天然,体验越好;反之不但不会提高体验,可能还会对用户带来困惑。

如何判断快照准确性

在每次生成快照时,咱们会将本次快照与上一次快照进行对比,得出量化的指标进而反映快照的准确性。那么下一步的问题就变成了如何判断两张图片的类似度了。

这里可能首先会想到直接使用像素逐个对比的方式来计算出两张快照中不一样像素点的比例,比例越高则快照越准确,但实际上这种方法没法体现出真正的类似度和用户的体感。例如,当两张快照位置只要稍有偏移,得出来的类似度值可能很低;或者是两张色差很小的快照,也可能获得不好的结果。而且,快照的像素数可能达到上百万量级,测试发现逐个的像素对比工做一次可能就会耗时数秒钟。

咱们如今使用了 Google 以图搜图中用到的“感知哈希算法”来量化快照的准确性。算法自己流程大体是将图片压缩后得出一些“指纹”信息,而后经过对比不一样图片的指纹信息计算出“差别指数”。差别指数越高,则说明两者类似度越低。此算法可以体现出两次快照的类似程度,而且其效率比像素逐个比对的方法有了极大提高,线上数据统计到整个算法的耗时不超过 3ms。

咱们对一些场景进行了实验并得出差别指数。能够看出,对于微小字符改变的场景,差别指数很是低;而有明显视觉差距的场景中,差别指数会变高。这样得出的量化值可以体现快照对用户带来的真实体感的影响。

场景差别指数视觉效果
少许字符变化 1
总体偏移 6

如何复原错误快照场景

可以感知快照的准确性后,对于准确性较差的快照,咱们还须要知道快照和真实页面相差在什么地方,进而改进快照的时机。

这里,咱们是经过获取快照时前端页面 DOM 树的方式来追查当前的真实页面状况。具体操做是在生成快照时获取当前小程序 HTML 页面脱敏后的 DOM 树信息,而后再依赖小程序框架的 CSS 文件,最后直接用浏览器就能够恢复出快照时的界面了

其它能力

局部快照

快照的一个比较大的局限性就是没法适应多变的首屏场景,这种场景使用快照很容易致使每次快照都没法跟真实首页重合,反而下降了用户体验。因此咱们考虑提供一种能力,只对首页中每次都基本不变的部分进行快照,而其它多变的部分不进行快照,这样也可以每次使首屏部份内容实现秒出。

例如钉钉里的人脉首页,上半部分是相对固定的展现,而下半部分 feed 流可能每次打开都会展现不一样的信息。那么在这种场景下咱们就不必每次都对整个首页第一屏进行快照,能够指定必定高度的部分进行快照,让首页的一部分实现秒出。

超一屏快照

当首页可滚动时,咱们甚至能够考虑超过一屏长度的快照,而且下次小程序启动时展现快照时让快照可滚动。此方案须要注意两个问题:

  1. 快照大小\
    线上统计显示,一屏的快照文件平均大小在 100K 左右。若是是超一屏的快照,大小可能会达到几百 K。须要在生成快照时预估一个长度上限或快照大小上限,以防快照使用时在低端机中出现 OOM 等异常状况。
  2. 快照滚动\
    若是快照在展现时用户进行了滚动操做,那么在隐藏快照时须要记录当前滚动的偏移量,以便将真实首页也滚动到指定位置,才能让快照和真实页面重合。

性能

对于快照的性能表现,咱们进行了实验室测试和线上的数据统计。

实验室测试中咱们构造了一个超大的快照(5.2M)的极限场景,并在低端机上与正常快照进行了对比:

普通场景极端场景
快照大小 262K 5.2M
内存占用 1840K 3245K
加载视觉体验 直接出现 有极短暂延时

快照加载过程并无影响正常的页面切换,只是在过大快照的加载可能有短暂的延时。

线上数据显示,带快照的页面加载耗时在 280ms 左右,快照的平均大小约 110K。

快照的生成和准确性检测等工做都是在异步线程中进行的,此时用户交互并未开始,而且在用户滚动、交互后不会进行快照,不会对性能形成太多影响。

这里还有个比较有趣的数据:用户对快照的平均点击次数是 0.6 次,首次点击时间约为 1500ms。也就是说,当快照展现 1.5s 后,有一半多的人会开始首次的交互。这也足矣说明让快照具有可交互能力的重要性。

展望

快照技术虽然缘起是为解决小程序启动性能问题,但实际运用场景能够扩展到更多地方。

理论上来讲,任何形式的异步渲染场景,不管是如今 WebView 仍是 weex 渲染的小程序,或者就是普通的 H5 网页,甚至是一些 native 的场景(须要 loading 的场景),只要是一块可以在客户端中展现的视图,都可以运用快照技术解决其过程当中的白屏或 loading 问题,而且都能作到秒出、可交互。由于快照是一个纯 native 的技术,它的实现原本就不依赖于真实页面的渲染方式,它更须要关心的是更合适的快照时机和应用场景从而获取更佳的体验。

总结

咱们提出了一种全新的小程序快照技术,实现了小程序首页的秒开和可交互。它可以完全消除小程序打开过程当中的 loading 或白屏现象,让小程序打开达到了 native 的体验,还能够响应用户点击交互。

它是一种纯 native 的技术,不依赖于小程序容器和前端的渲染,只要有视图就能快照,只要有快照数据就能当即展现,甚至可扩展运用于其它非小程序场景。

而其局限性主要是依赖首屏样式和快照时机选择,多变、含用户隐私数据的首屏不适合快照,并且优质快照的生成的时机要求比较苛刻。在快照准确性保障方面,快照的类似度对比方法上也仍然有很大的优化空间,这些都还须要在从此不断打磨。