前言這篇文章主要是對小程序官方文檔做部分深入解讀;讓大家了解小程序實現背后的機制原理。 由于筆者沒有獲取到微信官方提供的小程序實現原理圖,很多內容都是通過閱讀文檔資料反推和理解所得,如有誤解之處,望指正。 本文建議閱讀時間: 5min 目錄
小程序SDK官方文檔稱其為“基礎庫”。 這是一個很寬泛的名詞,只是覺得很重要,但說不好它具體有什么作用。我總結了 小程序5月帶給我的驚喜 ,它支持的功能也越來越豐富,體驗也越變越好,而這些動作如果用專業一點的術語概括就是“升級基礎庫”。 微信從開放內測到現在,微信基礎庫已經從的 v1.0.0 升級到了 v1.3.0 。 那么,“基礎庫”到底是什么東西? 小程序基礎庫提供豐富的微信原生API,可以方便的調起微信提供的能力,如獲取用戶信息,本地存儲,支付功能等。 這是官方對于“基礎庫”的定義。我們知道小程序的開發十分類似于現在的移動web開發,而移動web能使用到手機系統功能,app特色功能是非常有限的,而“基礎庫”的作用就是為了拓展小程序這方面能力,讓其功能與表現更接近原生app。 JS-SDK我們發現“基礎庫”的功能和微信的 JS-SDK 十分類似,順便再回顧下微信 JS-SDK 又是做什么的呢? 微信 JS-SDK 是微信公眾平臺面向網頁開發者提供的基于微信內的網頁開發工具包。通過使用微信 JS-SDK ,網頁開發者可借助微信高效地使用拍照、選取圖片、語音、位置等手機系統的能力,同時可以直接使用微信分享、掃一掃、卡券、支付等微信特色功能,為微信用戶提供更優質的網頁體驗。 小程序基礎庫與JS-SDK的共同點
小程序基礎庫與JS-SDK的不同點
小程序基礎庫查看方法官方API : getSystemInfo 、 getSystemInfoSync 。 wx.getSystemInfo({ success: function(obj) { obj = obj || {}; console.log('SDKVersion: ', obj.SDKVersion); }, fail: function() { console.error('[error]: getSystemInfo failed.'); } }); 返回對象中 SDKVersion 的值就是該微信版本攜帶的小程序基礎庫的版本號。 注意:該屬性在小程序版本 v1.1.0 才開始支持。 小程序基礎庫與客戶端之間的關系小程序的能力需要微信客戶端來支撐,每一個基礎庫都只能在對應的客戶端版本上運行,高版本的基礎庫無法兼容低版本的微信客戶端。 官方的這種說法存在一些問題?,F在基礎庫版本和客戶端版本并不是一一對應關系??蛻舳丝梢灾鲃由壭〕绦蚧A庫版本達到灰度上線新版的目的,所以必然存在一個客戶端版本對應多個基礎庫版本的情況。 小程序基礎庫更新時機為了避免新版本的基礎庫給線上小程序帶來未知的影響,微信客戶端都是攜帶 上一個穩定版 的基礎庫發布的。 在新版本客戶端發布后,我們再通過后臺灰度新版本基礎庫,灰度時長一般為 12 小時,在灰度結束后,用戶設備上才會有新版本的基礎庫。 以微信 6.5.8 為例,客戶端在發布時攜帶的是 1.1.1 基礎庫(6.5.7上已全量的穩定版)發布,在 6.5.8 發布后,我們再通過后臺灰度 1.2.0 基礎庫。 筆者使用的IOS設備更新到v6.5.8時對應的 SDKVersion 是 1.2.0, 但截止發稿日,該值已經變成了 1.2.4。 “細思恐極”,如果我們已經完成一臺裝有 6.5.4 版本微信的Oppo手機對小程序的兼容測試,很有可能過幾天這臺Oppo手機將小程序基礎庫更新到新版本導致小程序不可用。 建議:了解產品的用戶手機微信版本分布,確定回歸覆蓋范圍,完成回歸測試。 微信版本分布![]() ![]() 這是我們點餐小程序中用戶各版本微信的占比圖。通過這兩張圖我們能夠清晰的得出目前用戶使用的微信版本分布,就能夠制定針對性的測試覆蓋方案。 微信版本和基礎庫版本在 基礎庫更新時機 那小結我們提到,小程序的基礎庫和微信版本并不是一一對應關系,且隨著基礎庫和微信的不斷升級,它們的對應關系在時刻發生著變化。 下面是我整理的小程序基礎庫和微信版本對應表。 ![]() 開發者工具切換基礎庫版本![]() 在使用新API、新特性的時候,可以通過切換基礎庫版本完成兼容性測試。 wx 對象小程序基礎庫的所有功能全部封裝在 wx 全局對象中,開發者可以在小程序邏輯層代碼的任何地方調用該對象的方法。 看到 wx 對象,使用過 JS-SDK 的朋友表示很熟悉。我們在前面章節 小程序基礎庫與JS-SDK對它們做了簡單的比較,下面深入學習它們出于同源的技術: JsBridge 。 下一節,我們詳細講解一下 JsBridge 的原理和實現。 JsBridgeNative層需要暴露一些方法給js調用,比如,彈Toast提醒,彈Dialog,分享等等,有時候甚至把h5的網絡請求放著native去完成。原因很簡單,Native有更好的性能,更一致的表現和體驗。這就是 JsBridge 技術。 webview與客戶端的關系webview是客戶端的一個可調用的組件,且客戶端可以對webview做函數,事件的封裝,可以攔截webview的請求做統一控制,也可以向webview注入方法供JS調用等。 兩種 JsBridge 實現思路
通過這些方式能夠實現JS和客戶端通信,調起客戶端以及手機系統能力。 微信小程序 JsBridge 的實現wx 就是客戶端暴露給小程序的 JsBridge 接口。而這個封裝的 JsBridge 非常強大,它不僅僅支持toast,彈框等簡單功能,甚至包括網路 request 請求,緩存操作,手機硬件設備藍牙、重力感應等。下一個章節,我們介紹微信如何使用 JsBridge 、視圖層、邏輯層交互操作。 通信機制架構介紹![]() 這張圖展示了視圖層、邏輯層之間通信方式,以及 JsBridge 起到紐帶的作用。我們可以做以下幾點總結:
執行環境三端的js執行環境以及用于渲染非原生組件的環境是各不相同的:
這是官方關于視圖層和邏輯層運行環境的介紹。 視圖層(不包括Native組件)在webview組件中渲染;邏輯層的js代碼則通過js容器來執行。js代碼執行過程中可以通過JsBridge調起微信、系統的能力,也可以將數據通過 setData() 函數傳遞給視圖層做渲染。視圖層在渲染和交互過程中可以通過事件與客戶端進行通信。 視圖層向邏輯層的通信由事件來完成,而邏輯層數據向視圖層發送渲染指令是通過 Page 的 setData 函數。下面我們詳細說明他們的細節原理; 事件![]() 這張生命周期圖非常詳盡的描述了一個頁面從創建入棧、數據交互、銷毀出棧的整個過程。在頁面渲染和使用過程中會出現大量的事件,而這些事件會被JsBridge捕獲到,并傳遞給邏輯層處理,主要包括:生命周期事件、UI事件。 生命周期事件視圖進程在完成階段性工作后,需要向邏輯層同步其當前狀態以便邏輯層做出應對策略。主要包括: onLoad 、 onReady 、 onShow 、 onHide 、 onUnload 、 onPullDownRefresh 、 onReachBottom 、 onShareAppMessage 等。 UI事件視圖層向邏輯層的通信方式。 這類事件綁定在組件上,觸發則可以將用戶的行為反饋到邏輯層對應的注冊函數,如 bindtap、 bindinput 、 bindconfirm 、 bindfocus 、 bindsubmit 、 bindchange 、 bindlinechange 等 Page.prototype.setData()邏輯層向視圖層發送渲染指令的方式。 setData 函數用于將數據從邏輯層發送到視圖層,同時改變對應的 this.data 的值。 注意:data 將會以 JSON 的形式由邏輯層傳至渲染層,所以其數據必須是可以轉成 JSON 的格式:字符串,數字,布爾值,對象,數組。 從性能角度考慮,UI渲染是比較耗時的,一方面盡量減少頁面渲染操作,另一方面其會對 data的內容做深層次diff,盡量控制 data 的大小和數據結構的深度(官方限制 data 數據量最大為1024K。 筆者在做小程序性能監控的時候,遇到的一個問題就是無法準確統計到頁面渲染完成的時間。原因是 setData 函數只負責發送數據和渲染指令,但并沒有對應的反饋通知。 通過仔細分析,微信其實是可以提供這樣的能力的,在視圖層完成渲染后通過某種方式再告知邏輯層渲染狀態,我想出了兩個解決方案:
在和騰訊的同事提出該建議后,他們給出否定答案。原因是:回調函數會增加一次渲染層到邏輯層的通信開銷,而這個開銷相對而已比較重,目前他們官方是做了一些數據采樣,下圖是他們發給我們的渲染結果。 ![]() 總結本文通過對小程序基礎庫的介紹、拓展 JsBridge 到融會貫通,介紹基礎庫、視圖層、邏輯層的運行機制,就是希望大家能夠建立對小程序架構理解,了解各模塊在框架中所處位置和功用。 以上均為個人理解所得,由于沒有一些系統學習客戶端開發webview的經驗,所以關于 JsBridge 的一些講解比較淺顯,如有不當言論,望指出,謝謝。 -作者介紹- J文,美團點評點餐終端團隊C端組成員,負責大眾點評云餐廳微信小程序開發。 |