App內網頁靜態資源預加載 提升H5轉化率

一直以來, 咱們H5活動轉化率都很低; APP入口點擊 ->到達H5活動頁 轉化率只有 30% ~ 45%, 有很是大的提高空間;網頁應用啓動速度慢(尤爲是用戶首次訪問時)、點擊轉化率低等問題,使其難以進入核心業務技術選型。本文檔主要討論提升轉化率的具體落地方案;javascript

先來看一個例子:css

這是在中國wifi下打開咱們某個頁面 的h5的視頻,很快(算是吧,用PC打開,手機也同樣) 這是在印度辦公室打開的 html

可見。。。。。問題很是嚴峻。。。前端

下面咱們根據業界的方法,提出一下解決的愚見方法。java

最近咱們分析了一下整個加載過程的耗時(印度)react

WebView initialization Node router html/css/js CPR interface data/img(loading state) loading...whatever
500ms —— 1000ms 2000ms——3000ms 2000ms-3000ms It depends on the biz
無響應白色(低端手機估更長) 白屏(低端手機估更長),app上面一條加載線從webview到此UV流失率20%以上 白屏(低端手機估計更長),app上面一條加線從webview到此UV流失率50%以上 菊花/部分數據展現

問題一直存在。。。ios

具體方案

1. 隱藏WebView啓動模塊

此模塊由客戶端實現,主要功能:web

  • 在App啓動或進入導航類Native頁面時,初始化一個隱藏不可見的WebView組件,打開預加載器模塊H5頁面
  • 通常僅在網絡空閒、使用WIFI狀況下執行,以免佔用用戶正常訪問帶寬,節省用戶流量成本

2. 預加載器模塊

此模塊由Web前端實現,相似pwa的service worker.主要功能:typescript

  • 請求服務端接口,獲取須要預加載的靜態資源URL列表
  • 調用瀏覽器Fetch方法,下載列表中的靜態資源,存儲到WebView HTTP緩存區
  • 靜態資源下載完畢後,通知Native銷燬隱藏WebView
// 預加載器核心代碼示例
function prefetch(url) {
 return self.fetch == null
 ? xhrPrefetchStrategy(url)
    : fetch(url, { credentials: `omit` });
}
​
function xhrPrefetchStrategy(url) {
 return new Promise((resolve: () => {}, reject: () => {}) => {
 const req = new XMLHttpRequest();
 req.open(`GET`, url, (req.withCredentials = false));
 req.onload = () => {
 req.status === 200 ? resolve() : reject();
    };
 req.send();
  });
}
複製代碼

客戶端打開APP空閒時下載 白名單列表, 下載成功後緩存, 白名單可在  CMS 配置;前期考慮快速迭代, 白名單可先不配置,直接客戶端固定白名單; 白名單列表:json

const h5_white_list = [
  "https://a.com", 
  "https://b.mobi",
  "https://c.app"
];
複製代碼

3. 靜態資源URL列表配置模塊

此模塊由服務端實現,一般以管理配置平臺的形式,開放給全部業務線接入,主要功能:

  • 配置和管理須要被預加載的各網頁應用的URL列表
  • 組合全部接入方的URL列表,造成統一列表,提供給預加載器模塊調用
// URL列表配置接口示意

// 資源列表接口URL:https://www.company.com/prefetch-platform/config.json
// 資源列表接口響應體示例
// 實際返回給預加載器頁面的結果,須要對此配置中的assetsURL進行請求後,返回實際要加載的URL地址
{
 "prefetch": true, // 全局預加載開關
 "end":"appName"    //對應哪一個端
 "assets": [       // 資源URL列表
    {
      "name": "projectA", // 接入項目名稱
       "assetsURL": "https://www.company.com/projectA/prefetch-assets.json", // 接入項目資源列表接口地址
       "prefetch": true // demo項目預加載開關
    },
    {
      "name": "projectA",
      "assetsURL": "https://www.company.com/projectB/prefetch-assets.json",
      "prefetch": true
    }
  ]
}
複製代碼

接入方要接入App預加載功能,須要:

  • 項目上線時,構建生成本身項目的靜態資源URL列表
  • 設置靜態資源響應頭,容許預加載器跨域下載列表中的資源
// 接入方式示例

// 一、構建URL列表
// 資源列表接口URL:https://www.company.com/projectA/prefetch-assets.json
// 資源列表接口響應體:
{
 "prefetch": true, // 是否開啓預加載
 "end":"appA"  
 "assets": [    // 資源URL列表
    "https://www.company.com/projectA/js/index.abcd1234.js",
    "https://www.company.com/projectA/css/index.abcd1234.css",
    "https://www.company.com/projectA/img/index.abcd1234.png"
  ]
}
​
// 二、資源跨域頭設置
location ~* \.(html|js|css|png)$ {
 add_header Access-Control-Allow-Origin *;            
}
複製代碼

4. 針對HTML主文檔的預加載

上面咱們已經對網頁中的JavaScript/CSS等資源進行了預加載,咱們還須要對html進行預先加載 入口HTML一般設置爲不緩存,每次請求都會從服務端獲取最新內容。 這就致使HTML沒法進行預加載,進而致使整個網頁應用沒法實現離線化(斷網可用)。 要解決這一問題,咱們須要給HTML文檔增長版本號,並應用新的緩存策略。主要實現思路以下

a)在項目上線構建時,對 HTML主文檔/Node入口連接 增長版本號,並將帶版本號的入口地址URL,傳給服務端入口配置系統更新

例如: 服務器增長一個額外的接口

{
   currentVersion:1.0,
   project:'projectA',
   link:'https://gamewhateverstuff.app'
}
複製代碼

b) 經過服務端接口,下發帶版本號的入口URL

c) 客戶端對比版本號,肯定是否 預加載全部靜態資源(包括HTML)項目URL配置列表示例

// 配置URL示例
{
 "prefetch": true,
 "assets": [
   "https://www.company.com/projectA/index.20190501124536.html",
   "https://www.company.com/projectA/index.20190501124536.html?from=test",
   "https://www.company.com/projectA/js/index.abcd1234.js",
   "https://www.company.com/projectA/css/index.abcd1234.css"
  ]
}
複製代碼

對這些資源進行預加載後,即可以實如今用戶首次訪問頁面時,全部的靜態資源都從本地緩存讀取。主要收益:

  • 消除靜態資源下載帶來的網絡鏈接創建、數據傳輸等時間消耗,提升網頁應用啓動速度和點擊轉化率
  • 實現網站首頁徹底離線化,很大程度上解除應用對靜態資源服務器的核心依賴,提升系統可用性

d) 服務端API接口數據也能夠離線.對於頁面使用前端渲染的項目,除HTML/JS/CSS等靜態數據外,應用首次啓動通常還會有服務端API數據請求,此請求的離線化思路是:

  • 先嚐試網絡請求,失敗後走下一步
  • 從本地LocalStorge讀取(數據爲上一次正常網絡請求時存儲),若是讀取成功,則用上次的API數據渲染,並在頁面上展現網絡異常通知文案;若是讀取失敗,則走下一步;
  • 展現JavaScript代碼中內置的默認兜底數據,以及網絡異常通知文案

5.成本分析

因爲用戶瀏覽行爲的難以預測性,靜態資源預加載會帶來必定的流量浪費,須要對這部分紅本進行覈算。

1)企業下行帶寬成本

以預加載一個H5項目(資源大小100KB)1000萬次爲例,增長流量 = 1000萬 * 100KB ≈ 1TB

2)用戶手機流量成本

以預加載50個網頁項目爲例,增長的手機流量 = 50 * 100KB ≈ 5MB,僅在WIFI下載則用戶成本更低。 這裏須要指出的是,並不是每次App啓動都會下載5MB。在一個項目上線週期內,緩存資源失效前,僅會下載1次,後續資源預加載請求也會命中緩存。 預加載並不是適合全部的項目場景,不一樣項目的投入產出比是不一樣的,須要具體項目具體分析,以上給出的是成本分析的計算方法。 下面給出一些適用的項目場景:

  • 高點擊率、大流量網頁項目。高點擊率、大流量意味着高緩存命中、低流量浪費,如:點擊App首頁banner打開的熱點活動網頁
  • 對啓動速度和轉化率有極致要求的網頁項目。如:遊戲項目、其餘一些抽獎項目
  • 不適合的項目。流量小、轉化收益低的項目

6. 預加載策略

若是上述成本還沒法接受,咱們能夠經過靜態化和動態化策略,進一步降成本。

1)靜態化預加載策略

  • 僅下載大流量/重點項目
  • 僅WIFI環境和瀏覽器網絡空閒時下載
  • 在網頁啓動前,最近的上一步或上兩步Native頁面預加載,而不是都放到App啓動時下載
  • 僅預加載網站首頁須要的靜態資源,首頁以外後續其餘頁面的靜態資源,由網站首頁進行預加載
  • 按照項目配置的優先級順序分批下載,控制每次併發的下載鏈接數,響應緩慢時及時終止下載

上述部分策略,需經過服務端管理平臺落地,實如今合適的時機下載合適的項目。

2)動態化智能預加載策略

  • 基於用戶畫像(包括基礎畫像、長期畫像、用戶行爲軌跡、實時數據、歷史數據等),預測一個用戶將來會點擊哪些頁面,計算出將來訪問機率
  • 基於投放的面向用戶只投放給有門檻的用戶
  • 僅僅下載訪問機率高於特定閾值項目的靜態資源

動態策略舉例:僅針對未登陸用戶,預加載登錄網頁的靜態資源。 這裏須要指出的是,部分動態化策略的實現,須要大量研發資源和計算資源的投入,這部分投入可能已經遠遠超過了流量成本,所以在實施動態化策略時,須要綜合評估考慮。

7. 緩存命中率統計/覆盤

經過前端的性能監控系統Nemo Metric來得知請求的靜態資源是fromLocalCache仍是fromRemoteServer。 具體思路:performance.getEntries() ,能夠獲取每個靜態資源的請求信息,其返回以下圖:

  • fetchTime等於0 說明從緩存讀取 = fromLocalCache,fetchTime不等於0 說明從網絡讀取 = fromRemoteServer

緩存命中率 = fromLocalCache/ (fromRemoteServer + fromLocalCache) 這裏須要指出的是,緩存命中率只是一個過程指標,在項目初期,建議將更多精力關注到徹底加載時間和頁面加載成功率率等結果指標上。

8. App啓動時WebView內置公共基礎庫

在組件化、服務化盛行的今天,各個前端項目之間,共用了大量的基礎庫、組件庫、業務框架,對於這些共用的部分,能夠獨立成一組公共靜態資源,在App啓動時預加載,直接內置到WebView緩存中。 這些資源咱們在每一個H5項目都會用到

# 13kb
https://unpkg.com/react@16/umd/react.production.min.js
# 103kb
https://unpkg.com/react-dom@16/umd/react-dom.production.min.js
# 13.4kb
https://unpkg.com/axios/dist/axios.min.js
複製代碼

業務項目只須要引用這些地址,即可以直接從WebView緩存中讀取公共庫。

9. 與離線化/離線包方案的對比

在解決靜態資源下載慢這一問題上,業界還有一種廣爲應用的技術方案,既:離線化/離線包方案。其主要思路是:

  • 將包括HTML/JS/CSS等靜態資源打包到一個壓縮包內,在用戶訪問項目前,預先下載該離線包到本地並解壓
  • 當用戶訪問頁面發出資源請求時,WebView容器會對請求進行攔截,若是已經在離線包內,會使用離線包中的本地資源響應給用戶

若是在App啓動時進行預加載且App DAU很高,容易致使靜態資源服務器QPS激增,造成流量突刺形成宕機,須要作好流量預估,逐步放量。 針對於咱們目前這麼大的量,該方案成本高,不合適

10. 總結與指望收益

App應用的功能代碼,一般在用戶訪問以前,就已經以安裝包的形式,經過應用市場下載安裝好了。而網頁應用的功能代碼(靜態資源),則是在用戶實際點擊訪問時,才實時下載運行。

這一『用時下載』的特色是一把雙刃劍,既帶來了實時更新的靈活性,也形成了應用啓動的延遲,致使網頁應用啓動速度遠遠落後於App應用,形成交互體驗和用戶轉化短板。

本文提出的基於靜態資源預加載技術,提高App內網頁啓動速度的新方案。根據目前加載過程的耗時與流失請困高,此方案估計可顯著提高網頁啓動速度(縮短頁面加載時間30%-50%以上)、提升網頁加載成功率。

相關文章
相關標籤/搜索