Native 開發的諸多亮點中,流暢體驗和系統調用是最多被說起的。流暢體驗體如今頁面滾動/動畫的流暢性,背後是更好的內存管理和更接近原生的性能;同時又是 Web 的痛點:資源首次下載、長頁面內存溢出和滾動性能、動畫性能、傳統 web 性能(如JS執行效率)。Native 有豐富的系統調用能力,而 Web 痛點在於:W3C 標準太慢,有限的設備訪問能力,API 兼容性問題較嚴重,如 Geolocation 在 Android Webview 中可用性不好。css
Web 開發一樣有諸多亮點,其中最耀眼的當屬發佈能力和規模協做。Native App 商店審覈週期長(尤指 iOS);應用更新週期長,iOS 稍快大概能達到一週更新率 60%-80%,Android 一樣的更新率要2周甚至更長。而 Web 在合適的緩存機制下一分鐘可達到 99%+。瀏覽器內核 webkit 提供了相對一致的底層運行環境,html/js/css 控制頁面的結構/行爲/樣式,uri 鏈接不一樣的頁面,有了這些基礎設施,大規模的業務複用和人與人的分工協做變得相對輕鬆。html
同時今天阿里諸多客戶端已經面臨包大小接近臨界值,大促活動頁面(H5)體驗較差等一系列問題。結合 Native 和 Web 技術亮點,同時又能解決阿里遇到的業務問題,這就是 Weex 誕生的客觀環境。node
2016.11.11,在 1754 張雙11會場頁面中(統計了天貓和淘寶),Weex 頁面數爲 1747 佔比 99.6%。手淘 iOS/Android 分別有 83.5%/78.3% 版本(UV)啓用了 Weex 會場,手貓 iOS/Android 分別爲 91.7%/87.9% 版本(UV)。Weex 覆蓋了包括主會場、分會場、分分會場、人羣會場 等在內幾乎全部的雙11會場業務。react
在這樣的應用規模下,工做和目標是:android
1. 業務支撐,支撐住雙11需求,這是最基本的要求,詳見下文「業務支撐」一節ios
2. 穩定性保障,Weex 引起的問題第一時間響應並處理,不留到雙11當天,詳見下文「穩定性數據」一節git
3. 秒開實戰,穩定當先力爭高性能,雙11正式主會場秒開率衝到 97%,全部會場秒開率衝到 93%,詳見下文「秒開數據」github
2016 雙11會場的感覺可查看原始錄屏文件:WIFI | 4G | 3G | 2G | 無網絡 。錄屏時主會場已是預加載版本,其中 WIFI 和 4G 效果接近,2G 效果取決於數據的網絡請求速度(錄屏時數據請求約3.9s),無網絡狀況下打底數據來自前一次成功請求。流暢性可查看該視頻,左起爲 H五、iOS Weex、Android Weex。web
展開 Weex 雙11細分目標:npm
圖 - Weex 雙11細分目標
支撐住雙11的業務需求,是 Weex 必需要邁過的坎。
雙11的會場結構大體爲:會場框架(框架 + 主會場、所有會場、必搶、清單、個人雙11)、分會場、其餘會場(分分會場、人羣會場等)。
Weex 支撐雙11業務首要解決的是會場框架及其交互形式:
1. 交互主流程:
1. 非 push 方式(框架Tab 切換):主會場 - 所有會場 - 必搶 - 清單 - 個人雙11
2. push 方式:主會場 - 分會場 - 主會場
2. iOS 考慮到內存開銷,需嚴控打開的主分會場weex頁面,定爲 n 級可配,默認爲 5;同時 iOS 會場框架爲單實例,也是出於內存的考慮;Android 連續打開 30 級以上 Weex 頁面,未見內存異常增加,無需特殊方案
圖 - 會場框架交互
Weex 會場框架很好支撐住了雙11的複雜交互需求並提供了更好的內存管理。除了會場框架,更多的 Component 和 Module 支撐住了各色各樣的雙11需求,這裏僅列出幾個表明:
1. List 組件是幾乎全部會場頁面的標配,流暢的滾動幀率、高性能的內存複用機制和渲染機制是頁面流暢體驗的重要基礎
2. Animation 儘管是實驗版需求,卻支撐住了會場的垂直彈幕、坑位顯隱等動畫效果,動畫效果細膩
3. Weex 點播/直播組件 和 全景圖組件支撐住了更爲垂直個性化的業務需求
上節內容也能夠看出,參與 Weex 雙11會場涉及多個團隊和平臺系統:
圖 - Weex 雙11中組織結構
1. 天貓業務:經過斑馬(活動頁面搭建和發佈平臺)發佈會場頁面
2. 淘寶業務:經過斑馬和 AWP (產品頁面發佈平臺)發佈會場頁面,上層 DSL 使用 Rx(即將開源)
3. 預加載:提早將會場 js-bundle 下載到客戶端,客戶端訪問 Weex 會場時網絡 IO 被攔截到本地文件 IO,從而極大加快了網絡加載速度,預加載是此次秒開實戰的抓手(注:最核心的工做)
4. 手淘、手貓客戶端,Weex 是客戶端的一部分,客戶端中實際上是 Weex、Native、H5 並存的
5. Weex SDK、業務模塊:Weex 容器和基礎的 Components、Modules,業務模塊包括直播/點播組件、全景圖組件
以上也僅涉及到客戶端和發佈端,背後還有無數的業務後臺系統,就不一一列出了。
將 Weex 架構自上而下地展開:
1. Business,Weex 業務層,Weex 雙11主戰場是手淘和手貓,此外還有大量客戶端已經啓用或接入了 Weex
2. Middleware,Weex 中間件層,包括爲 Weex 頁面提供發佈(斑馬、AWP)、預加載(AWP)、客戶端接入支持(AliWeex)、組件庫(SUI)、遊戲引擎、圖表庫等模塊;其中斑馬、AWP、預加載都直接參與了雙11
3. Tool,工具層
1. DevTools,界面和交互複用了 Webkit Devtools,支持 elements、network、斷點、console 等
2. Playground,方便開發者調試 Weex 頁面,同時也是 Weex example 的彙集地
3. Cli,Weex 命令行工具集
4. 目前仍在建設更多的工具,如 weex-pack 支持一鍵打包成 App
4. DSL
1. JS Framework,Weex 最初的 DSL 是基於 Vuejs 1.0 語法子集;目前在社區中在推動基於 Vuejs 2.0 的版本
2. Rx,基於 reactjs 語法的 Weex DSL(將於12 月正式開源)
5. Engine,渲染引擎,從架構設計上,Android/iOS/H5 RenderEngine 是相互獨立和平等地位的渲染端,這是保持三端一致的基礎,固然在協議實現層面須要更多的設計、質量保證。
圖 - Weex 架構
以上就是 Weex 在雙11中的架構和業務支撐的範圍了。
Weex 的首要挑戰就是穩定性,或者說保障 Weex 會場最大限度不降級。
8月初(同期雙11啓動)奧運大促時,手淘 iPhone 中反覆進出會場20+(手貓15+),會出現 crash。奧運大促當天,手淘 iOS 1.59% crash 次數來自該問題(top 6),手貓1.94%(top 8)。發現問題的當天成立了攻堅小組,從 JS業務代碼、JSFM(框架)、iOS 渲染、iOS JSCore 幾個方向同時排查,一週內各方向排查到逐步收斂到:根本緣由是 Weex 頁面實例被全局持有(weex runtime 只有一份),進而致使頁面退出時內存不被釋放,反覆進出直至內存爆掉。於是任何可能致使頁面實例被全局持有的因素都會觸發這個問題:
1. 業務代碼中的問題,意外致使的,給出 Lint 工具掃描業務代碼,引入了「全局污染治理」(見下一節)
2. JSFM 框架中的問題,如在 destroyInstance 時清理 commonModules 和全部 dependency target;iOS7下的 Set Polyfill 內存飆升問題
3. iOS 中的問題,經過下發配置控制 VC Push層級控制;內存警告時的非當前實例銷燬策略,加入開關控制;iOS 9.x JSCore 原生 Promise 和 Polyfill 並存時的內存問題
除了創建攻堅團隊推動解決該問題,也在造勢期前就展開雙11會場壓測,反覆驗證該問題,自雙11造勢期會場開測以後,該問題未再出現。
在治理 JSCore 內存的過程當中,逐步意識到對全局變量管控的必要性。Weex 中多個頁面共用 1 個 runtime,單個頁面若是寫法不規範不只可能致使內存泄露,更有可能污染全局環境,進而致使全部 Weex 頁面沒法正常工做。全局污染治理的核心抓手:
1. 嚴格模式,即 `use strict`,使用嚴格模式能夠將較多常見的 JS 陷阱轉化爲錯誤,如:沒法再意外建立全局變量、將拼寫錯轉成異常、限制了 eval 的能力 等
2. 冰凍對象,利用 ES5 的 `Object.freeze()`,將 Weex 核心對象和 JS 原生對象「冰凍」住。嘗試修改被「冰凍」的對象會拋出錯誤,一旦「冰凍」沒法「解凍」。
Weex 經過 Adapter 來適配不一樣客戶端的具體實現,諸多通用庫,如:網絡庫、圖片庫、API 庫、 H5容器(Web 組件)、埋點庫、配置庫 等在不一樣客戶端上版本不一致,所以致使的線上問題將會成爲雙11會場的隱患。爲此展開的依賴梳理和同步機制是雙11穩定性的保障之一。這件事情可能將會長期出如今 Weex 問題清單之中,如何作到上層 Weex SDK
* 壓測場景
1. 5 個 200 坑位的普通會場頁面,1 全景圖會場頁面,1 UT Expose 壓測頁面,1 直播會場頁面
2. 頁面中提供連接,可以按順序進行 push 跳轉
* 壓測方案
1. 主鏈路(首頁->店鋪->詳情->購物車)作一遍操做,讓內存緩存佔滿,記下內存值 M0
2. 進入 Weex 頁面,滑動到底部,滑動到頂部,記下 M1;點擊跳轉按鈕,跳轉到下一個頁面
3. 重複步驟 2,讓全部的頁面進行壓棧;全景圖->p1p2p3p4->直播->p1p2p3p4->UT
* 壓測結果:iOS 經過,Android 經過
1. 測試過程手淘手貓均未出現由於壓棧致使的 Crash,穩定性能夠保證;
2. Android低端機壓棧過多會致使體驗較差,以後也會引入相似 iOS VC 層級控制;
壓測在造勢期會場測試階段展開,在超出真實會場壓力的狀況下(真實會場150坑位上限),儘量提早嗅探出潛在的 iOS JSCore 內存問題、iOS/Android 異常閃退等細節問題。
2016.11.11,Weex 在手淘中的 Crash 佔比狀況:
* iOS 1.46%(TOP7)
* Android Java Crash 0.85%(TOP13)、Native Crash 1.72%(TOP8)
考慮到會場的業務量級,Weex 的穩定性仍然是不錯的。注:單獨計算的 Weex Crash 率過小,參考價值不大。
Weex 秒開率 = (加載時間 + 首屏渲染時間)< 1s 的比率
其中:加載時間指 Weex js-bundle 的加載時間(從網絡下載或本地加載);首屏渲染時間指 Weex 頁面開始渲染到第 1 個元素 bottom 超出首屏範圍的時間。下文提到的「首屏網絡時間」爲加載時間與首屏渲染時間的和。
從雙11結果看預加載大幅度提高加載時間,對秒開率的貢獻尤爲突出;但性能優化是個長期迭代的過程,回頭來看優化的抓手是:預加載和首屏渲染優化。
預加載解決了 1 個問題:
用戶訪問頁面(H5/Weex)以前,將頁面靜態資源(HTML/JS/CSS/IMG...)打包提早下載到客戶端;用戶訪問頁面時,將網絡 IO 攔截並替換爲本地文件IO;從而實現加載性能的大幅度提高。
啓用預加載後加載時間的變化,粗算一下:手淘 iOS,走網絡平均 296ms,走預加載 18ms,網絡性能提高約 15 倍;手淘 Android,走網絡平均是 696ms,走預加載是 54ms,網絡性能提高約 12 倍,但絕對值更大,對 Android 會場秒開貢獻更爲突出。
2015年預加載已經在雙11 H5 會場中有較多應用,2016 年預加載升級爲一項基礎服務,不只爲 WindVane 提供預加載能力,也成爲 Weex 秒開的最強外援。
這次雙11會場共啓用 30 個預加載包,總容量超過 20MB,業務需求相對穩定且流量較大的幾個頁面(會場框架+主會場 等)是獨立的包,保證了對總體秒開的貢獻,其餘分會場均分在剩餘的包中。同時主要採用強制更新的策略,即新的資源包(服務端有新發布)未下載到本地就直接讀取線上,能夠保證業務的實時性。2016.11.11,雙11會場中 Android 走預加載佔比爲 59.4%,iOS 爲 62.5%,高於平均水平(但還能夠更高)。
首屏渲染優化的目標就是盡力縮短首屏的渲染時間,爲此在一系列的優化過程當中,能夠粗分爲:DOM 解析優化、UI 渲染優化、分段懶加載。
* Component append 屬性定義了 `node` 和 `tree` 2 種渲染模式,`node` 就是逐個節點渲染, `tree` 就是整棵樹一塊兒渲染。直觀的對比:node | tree。
* `node` 模式,節點逐個從 js 提交到 native 的, native 側有個 16ms 間隔的 layout 保證渲染的正確性,這是更接近於 WebKit 的一種解析渲染模式。優點是每個被解析完的節點均可以馬上顯示,同時保證不會長時間阻塞主線程,劣勢是可能會形成屢次冗餘 layout,拉低流暢性。
* `tree` 模式,整棵樹(以當前節點爲 root 的整棵樹)從 js 提交到 native。優點是隻需佈局一次,渲染更高效;劣勢是若是 tree 過大,就可能會阻塞主線程甚至阻塞渲染。
* `node` 和 `tree` 能夠精細化地控制頁面展現的邏輯和顆粒度,典型的實踐爲首屏之內按 tree 解析,首屏之外按 node 解析。
* List 組件在 native 分別對應 iOS UITableView 和 Android RecyclerView,這兩種 View 構建了 App 的半壁江山,使用它們來封裝 list 的好處:
* 只會渲染可見區域,減小首屏的渲染消耗
* 內存複用,全部滑動到不可見區域的 cell 都會被系統回收,用於渲染下一個 cell
* cell 之間自然互相隔離, 能夠默認以 cell 維度劃分並用 tree 的模式解析,提升渲染效率
* 擁有原生的交互體驗,在 cell 上點擊、左滑、右滑、移動排序等交互方式後續能夠更方便地支持
* 想要達到 60FPS 的體驗,一次主線程渲染必須少於 16ms。Weex 中一次渲染須要通過 6 個主要步驟(Build Tree、Compute Style、CSS Layout、Create View、Update Frame、Set View Props),因此必須在 16ms 內完成這 6 個步驟,現實是任何一步在主線程中均可能超過 16ms,這塊。
* 除了底層的優化,業務上也經過分段懶加載進一步下降總體渲染時間,對首屏渲染有間接幫助(減小調度)
* 方案爲:會場頁面使用 List 進行佈局,一個 cell 對應一個模塊;頁面啓動默認加載 6 個模塊(少數頁面由於首屏模塊過多所以特殊處理);默認往下滑到底觸發 loadmore 後再加載 5 個模塊;若加載過程當中遇到電梯則電梯如下模塊所有加載
除了底層的保障,咱們也堅持天天產出「性能優化建議」,推動業務性能優化,接下來會有更加方便的工具提供給業務方直接性能調優;如雙11期間 devtool 中增長了層級檢測和告警,能夠幫助排查深層級致使的 android 低端機 stackoverflow。
因爲主會場流量佔據了總流量的大部分,對其秒開率單列統計。2016.11.11 數據爲:
主會場
全部會場
Weex 技術委員會在十月中成立了,核心解決 Weex 開發過程當中的標準化和協同問題。並於10.26 進行了第一次會議,審議的 4 個話題(Input focus/blur、750px實現方案、weex analyze後續發展、標準化流程草案)通過充分討論,均得到全員投票經過。
鬼道做爲第一任組長,接下來半年帶領各方推動 Weex 在集團和社區的深度建設,歡迎你們參與 Weex 的共建之中。對於參與 Weex 的各方而言,最直接的影響就是:須要做爲 Weex 官方推薦,向集團或(和)外部社區貢獻的 Module、Component、工具、平臺 等成果 須要經過 Weex 技術委員會檢視標準性。要求在 方案設計出來後實現以前 和(或) 實現出來後 這 2 個時間點向 Weex 技術委員會彙報標準性相關細節;這個要求是強制的,目的是保持 Weex 社區的標準化推動。若是你只是爲局部業務開發定製化的 Weex 擴展,不涉及標準性,並不會被要求到 Weex 技術委員會彙報。
Weex 任重道遠:
1. Weex 不僅是 Weex 容器,Weex 業務背後是發佈、預加載、AB、線上監控、質量效能度量、數據埋點、業務開發技能轉變/升級 等一系列行爲的交織,如何減小業務從 H5/Native 轉向 Weex 時的「陣痛」,是接下來的攻堅重點
2. 雙11中遇到的典型案例或問題,會成爲下一階段的工做重點之一
3. 仍有大量業務需求須要開發,爲此咱們已經啓動了 Weex BigBang 項目,按照 WindVane API 的調用頻度和業務反饋狀況,分批實現 30+ Weex Module/Component,包括經常使用的 schema 喚起支持、網絡類型判斷、geolocation、audio、cookie、大圖預覽、通信錄 等
4. 減小新客戶端接入 Weex 的成本,目前在嘗試的 AliWeex 項目會擴大應用範圍併成爲客戶端接入的標配
5. 跨客戶端的底層依賴不一樣步問題會一直存在下去,須要更好的解法
不一一列舉了,以後會有 Weex Roadmap 的討論而且會及時公佈出來,歡迎關注。
從「Native 和 Web 融合」開始,前後經歷的 Hybrid、React Native、WVC 再到 Weex,這段經歷也算挺戲劇性的;將來會是 Weex 嗎?答案並不重要,惟有沉醉其中。