釘釘小程序快照技術初窺

{"type":"doc","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/c7/c7c73a83994db10394f5998ded9b8b81.gif","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"作者:孫然(煮蝦)","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"對於小程序技術來說,容器加載和前端異步渲染的過程中固然不可避免的會有白屏或 loading 頁的展示,短則一瞬間,長則需要數秒才能展示首屏。如果白屏時間長,將非常影響用戶的體驗。根據 Google 的統計,如果頁面加載耗時超過了 3s,那麼有 53% 的用戶會選擇直接退出該頁面了。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"爲加速小程序首頁的展示,支付寶和手淘運用了基於 HTML 的","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"快照","attrs":{}},{"type":"text","text":"技術,主要思路都是緩存首頁 HTML 供下次啓動時與數據一起優先渲染以提前首屏展示的時間,適用於傳統 WebView 渲染的小程序場景。這種基於 HTML 的快照技術能夠極大縮短啓動時的白屏時間,但首屏展示的速度還是不夠快,期間用戶仍然會有可見的白屏感受。並且快照展示的仍然是無法點擊操作的頁面,需要等待 JS 部分 ready 後纔可點擊交互。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"爲了追求極致的體驗效果,我們提出了一種全新的小程序快照技術,目標是既做到徹底消除白屏現象,同時也要能夠響應用戶交互。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/df/df3085abafd46a54300a1f91ebd644bb.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"核心思路","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"不同於現有的基於 HTML 的快照技術,我們提出了一種 native 的圖像級別的快照技術,主要由以下三個步驟:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"步驟1:在小程序啓動後合適的時機將小程序首頁保存爲圖片,我們稱之爲","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"快照","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"步驟2:下次打開小程序時先展示上次保存的快照,再啓動小程序","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"步驟3:當小程序啓動完後的合適時機,隱藏快照,展示出真實的小程序首頁,並保存當前界面視圖作爲下次的快照(同步驟1)","attrs":{}}]}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/40/40269935c71d3c7491c20886d174d1e5.jpeg","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"效果","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"現在釘釘中的新建 DING 日程頁面就運用了快照技術,前後效果對比如下:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/f5/f504e1b275abee4e728da42b03982806.gif","alt":null,"title":"","style":[{"key":"width","value":"25%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":"center","origin":null},"content":[{"type":"text","text":"before","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/1b/1b3e7716f9511162456c4979d1a46a6e.gif","alt":null,"title":"","style":[{"key":"width","value":"25%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":"center","origin":null},"content":[{"type":"text","text":"after","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":"center","origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"可以看出,通過快照技術,該頁面實現了首屏秒開的效果,啓動白屏的現象徹底消失,頁面的首屏渲染耗時從 1700ms 左右降低到了 300ms 以下。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"下面我會對快照技術的幾個關鍵考慮點進行詳細介紹。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"場景和時機","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"理想中的快照,應當是能夠和首屏頁面完全重合,並且在快照隱藏時不會產生任何視覺變化的。那麼生成快照的","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"時機","attrs":{}},{"type":"text","text":"和運用快照的","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"場景","attrs":{}},{"type":"text","text":"就直接決定了快照技術能夠達到的優化效果。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"什麼頁面適合用快照?","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"並不是所有的小程序都適合使用快照技術來提升首屏體驗。如果使用不當,快照可能還會成爲體驗的減分項。爲達到最佳效果,一般首屏頁面滿足下面幾個條件是比較適合使用快照的:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"首屏頁面較爲固定。如果首屏不固定,很難找到合適的快照時機來保證快照與下次的首屏重合","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"首屏頁面不含用戶隱私數據。用戶的隱私數據不應當被快照下來","attrs":{}}]}]}],"attrs":{}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"什麼時候生成快照?","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果快照的時機過早,快照可能展示的也是白屏或者未渲染完整的首頁框架。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果快照的時機過晚,可能用戶已經對首屏有了交互(滾動、點擊等),容易生成無法和首屏重合的快照。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"所以需要根據不同的首屏場景來確定最佳的快照時機。一般我們考慮快照的時機有:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"小程序首屏 Page 的 onReady 生命週期回調裏。但此時頁面很可能仍然沒有渲染完成,可以考慮適當延時後進行快照","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"小程序首屏的數據如果需要遠程拉取,可以在遠程獲取到首屏數據後進行","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"用戶發生滾動時、點擊等交互後不再進行快照","attrs":{}}]}]}],"attrs":{}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"什麼時候隱藏快照?","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們一般考慮在","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"生成快照時","attrs":{}},{"type":"text","text":"去隱藏當前已經展示的快照。二者的順序一般是在隱藏快照後立即生成快照,才能實現快照和真實頁面的無縫銜接。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"當然,也需要考慮小程序啓動可能失敗的場景。這裏需要對展示快照的時間設置一個展示的上限,如果展示時間達到上限時小程序首屏仍然沒有啓動成功,那麼快照將直接隱藏,以防造成首屏對用戶可見但一直不響應的尷尬局面。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這裏我們在還隱藏快照時做了一個小小的視覺優化。考慮到在隱藏快照時,如果直接隱藏快照,一旦快照和真實頁面稍有差別,在視覺上可能就會有閃爍的體感發生。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"所以在隱藏快照時,我們會做一個 200ms 的淡出動畫,來緩解這種快照和真實頁面差異導致的閃爍感。因爲有時快照的時機可能會稍提前於首頁網絡數據加載成功、圖片加載成功等這些異步事件成功的時機,導致快照比真實頁面元素缺少或者數據不準確,而淡出動畫能夠有效淡化這些差錯造成的視覺異常感。下面的 demo 對比了這兩種情況:","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/9c/9c9038f01bf0a949be831955688950ab.gif","alt":null,"title":"","style":[{"key":"width","value":"25%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":"center","origin":null},"content":[{"type":"text","text":"直出","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/3a/3adccb69ad306ad9accadc0d9415e207.gif","alt":null,"title":"","style":[{"key":"width","value":"25%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":"center","origin":null},"content":[{"type":"text","text":"淡出","attrs":{}}]},{"type":"embedcomp","attrs":{"type":"table","data":{"content":"
直出淡出
\"\"\"\"
"}}},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"可交互","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"由於快照和真實的首屏頁面基本是相同的,從用戶體感上用戶會以爲首屏已經成功展現,也應該是個可交互的頁面。所以","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"單純展示死的快照頁面是遠遠不夠的,做到可交互是我們快照的重要能力","attrs":{}},{"type":"text","text":"。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們的快照支持響應用戶的點擊行爲,具體方法就是在用戶點擊快照時先暫存用戶的點擊事件,待快照隱藏時將此次事件分發到真實頁面上去。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/c6/c6671688b4f97e9aed0da041c80eb59d.jpeg","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"此過程中如果用戶有多次點擊事件,我們只會響應最後一次點擊事件。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"從用戶體感上來說,可能用戶會感覺到此次點擊的響應會比較慢,但不會讓用戶感知到它點擊的是快照還是真實首頁。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果是小程序啓動較慢的場景,還可以考慮在用戶點擊後展示 loading:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/35/3541c526544d84f7bfe8903482763eee.gif","alt":null,"title":"","style":[{"key":"width","value":"50%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"爲進一步提高快照層的可交互性,我們甚至還可以允許開發者設定一些快照層的點擊區域和簡單操作,使用戶在點擊快照層的時候快速響應點擊事件。例如釘釘的工作臺就非常適合這種場景:工作臺中的各個應用一般不會頻繁變化,並且有很明確的分塊區域:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/60/60bceb9d5850f7659094dd81dbe49fc9.jpeg","alt":null,"title":"","style":[{"key":"width","value":"50%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"可以配置好不同的點擊區域以及對應的 action (例如:跳轉到其它頁面/應用),形如:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"[{\n area: {\n left: 100, \n top: 100, \n width: 100, \n height: 100\n },\n action: {\n type: 'openLink', \n params: { url: 'http://xxx' }\n }\n}, ...]\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這樣用戶在點擊快照指定區域時就能直接實現跳轉,而無需等待到小程序啓動完成。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"存儲與安全","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"快照屬於敏感數據,並且只保存在客戶端本地不能進行上傳,管理其存儲必須格外小心,否則很容易釀成一起公關事件。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"對於快照的存儲,我們考慮了以下幾點:","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"加密存儲","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"快照數據必須進行","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"加密存儲","attrs":{}},{"type":"text","text":",這裏加密方式用的是集團無線保鏢裏的加密方法。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"隱私保護","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"快照裏不能含有用戶的隱私數據。也就是說,快照應當只含有一些 UI 元素或者無意義的默認數據,而不應該含有用戶隱私數據。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/44/44375444526d48d5f58123123b24fcae.png","alt":null,"title":"","style":[{"key":"width","value":"25%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":"center","origin":null},"content":[{"type":"text","text":"不含用戶隱私數據","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/93/936bb93d1bd0d396ce1ea8fe5480fe5b.png","alt":null,"title":"","style":[{"key":"width","value":"25%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":"center","origin":null},"content":[{"type":"text","text":"含用戶隱私數據","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"那麼如何做到獲取到不含用戶隱私數據的首頁快照呢?可以考慮在前端從網絡、緩存中獲取數據之前進行快照。但這樣的快照必定是不完整的,會損失一定的體驗,這也是我們不推薦在有用戶數據的首屏場景使用快照的原因。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"快照清理","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"快照被存儲在客戶端中,需要有存儲上限。當快照數據達到一定量後,需要淘汰一些老的快照數據。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"其次,在小程序版本更新、用戶登出切換用戶時都應該考慮將現存的對應快照數據清理掉。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"準確性","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"當快照上線後,我們需要對快照的用戶體驗進行感知。最佳的體驗是用戶根本就沒有感知到快照的存在,也就是快照和真實頁面完全重合;而如果快照和真實頁面相差較大,則會讓用戶體驗大大下降,這是我們需要感知到的。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這裏我們主要關注快照的","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"準確性","attrs":{}},{"type":"text","text":"指標,也就是快照和真實頁面的相似(重合)程度。準確性越高,則說明快照與真實頁面的過渡約自然,體驗越好;反之不但不會提升體驗,可能還會對用戶帶來困惑。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"如何判斷快照準確性","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在每次生成快照時,我們會將本次快照與上一次快照進行對比,得出量化的指標進而反映快照的準確性。那麼下一步的問題就變成了如何判斷兩張圖片的","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"相似度","attrs":{}},{"type":"text","text":"了。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這裏可能首先會想到直接使用像素逐個對比的方式來計算出兩張快照中不同像素點的比例,比例越高則快照越準確,但實際上這種方法無法體現出真正的相似度和用戶的體感。例如,當兩張快照位置只要稍有偏移,得出來的相似度值可能很低;或者是兩張色差很小的快照,也可能得到很差的結果。並且,快照的像素數可能達到上百萬量級,測試發現逐個的像素對比工作一次可能就會耗時數秒鐘。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們現在使用了 Google 以圖搜圖中用到的“感知哈希算法”來量化快照的準確性。算法本身流程大致是將圖片壓縮後得出一些“指紋”信息,然後通過對比不同圖片的指紋信息計算出“差異指數”。差異指數越高,則說明二者相似度越低。此算法能夠體現出兩次快照的相似程度,並且其效率比像素逐個比對的方法有了極大提升,線上數據統計到整個算法的耗時不超過 3ms。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/e1/e18c09854132776f414b26799c3108cc.jpeg","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們對一些場景進行了實驗並得出差異指數。可以看出,對於微小字符改變的場景,差異指數非常低;而有明顯視覺差距的場景中,差異指數會變高。這樣得出的量化值能夠體現快照對用戶帶來的真實體感的影響。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"如何復原錯誤快照場景","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"能夠感知快照的準確性後,對於準確性較差的快照,我們還需要知道快照和真實頁面相差在什麼地方,進而改進快照的時機。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這裏,我們是通過獲取快照時前端頁面 DOM 樹的方式來追查當前的真實頁面情況。具體操作是在生成快照時獲取當前小程序 HTML 頁面","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"脫敏","attrs":{}},{"type":"text","text":"後的 DOM 樹信息,然後再依賴小程序框架的 CSS 文件,最後直接用瀏覽器就可以恢復出快照時的界面了","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/3f/3f3c5d25057d2382e6a10b6ac57f73d3.jpeg","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"其它能力","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"局部快照","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"快照的一個比較大的侷限性就是無法適應多變的首屏場景,這種場景使用快照很容易導致每次快照都無法跟真實首頁重合,反而降低了用戶體驗。所以我們考慮提供一種能力,只對首頁中每次都基本不變的部分進行快照,而其它多變的部分不進行快照,這樣也能夠每次使首屏部分內容實現秒出。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"例如釘釘裏的人脈首頁,上半部分是相對固定的展示,而下半部分 feed 流可能每次打開都會展示不同的信息。那麼在這種場景下我們就沒必要每次都對整個首頁第一屏進行快照,可以指定一定高度的部分進行快照,讓首頁的一部分實現秒出。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/fe/fed78a66b8e67bdeef3e684c84f97742.png","alt":null,"title":"","style":[{"key":"width","value":"25%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"超一屏快照","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"當首頁可滾動時,我們甚至可以考慮超過一屏長度的快照,並且下次小程序啓動時展示快照時讓快照可滾動。此方案需要注意兩個問題:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"numberedlist","attrs":{"start":1,"normalizeStart":1},"content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"快照大小","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":"none"},"content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"線上統計顯示,一屏的快照文件平均大小在 100K 左右。如果是超一屏的快照,大小可能會達到幾百 K。需要在生成快照時預估一個長度上限或快照大小上限,以防快照使用時在低端機中出現 OOM 等異常情況。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"快照滾動","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":"none"},"content":[{"type":"paragraph","attrs":{"indent":0,"number":4,"align":null,"origin":null},"content":[{"type":"text","text":"如果快照在展示時用戶進行了滾動操作,那麼在隱藏快照時需要記錄當前滾動的偏移量,以便將真實首頁也滾動到指定位置,才能讓快照和真實頁面重合。","attrs":{}}]}]}]},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"性能","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"對於快照的性能表現,我們進行了實驗室測試和線上的數據統計。快照加載過程並沒有影響正常的頁面切換,只是在過大快照的加載可能有短暫的延時。線上數據顯示,帶快照的頁面加載耗時在 280ms 左右,快照的平均大小約 110K。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"快照的生成和準確性檢測等工作都是在異步線程中進行的,此時用戶交互並未開始,並且在用戶滾動、交互後不會進行快照,不會對性能造成太多影響。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這裏還有個比較有趣的數據:用戶對快照的平均點擊次數是 0.6 次,首次點擊時間約爲 1500ms。也就是說,當快照展示 1.5s 後,有一半多的人會開始首次的交互。這也足矣說明讓快照具備可交互能力的重要性。","attrs":{}}]}],"attrs":{}},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"展望","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"快照技術雖然緣起是爲解決小程序啓動性能問題,但實際運用場景可以擴展到更多地方。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"理論上來說,任何形式的異步渲染場景,不論是現在 WebView 還是 weex 渲染的小程序,或者就是普通的 H5 網頁,甚至是一些 native 的場景(需要 loading 的場景),只要是一塊能夠在客戶端中展示的視圖,都能夠運用快照技術解決其過程中的白屏或 loading 問題,並且都能做到秒出、可交互。因爲快照是一個純 native 的技術,它的實現本來就不依賴於真實頁面的渲染方式,它更需要關心的是更合適的快照時機和應用場景從而獲取更佳的體驗。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"總結","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們提出了一種全新的小程序快照技術,實現了小程序首頁的秒開和可交互。它能夠徹底消除小程序打開過程中的 loading 或白屏現象,讓小程序打開達到了 native 的體驗,還可以響應用戶點擊交互。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"它是一種純 native 的技術,不依賴於小程序容器和前端的渲染,只要有視圖就能快照,只要有快照數據就能立即展示,甚至可擴展運用於其它非小程序場景。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"而其侷限性主要是依賴首屏樣式和快照時機選擇,多變、含用戶隱私數據的首屏不適合快照,而且優質快照的生成的時機要求比較苛刻。在快照準確性保障方面,快照的相似度對比方法上也仍然有很大的優化空間,這些都還需要在今後不斷打磨。","attrs":{}}]}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章