在開發小程序應用中,QA發現過幾回頁面白屏的狀況,苦於難易復現和調試,故想對小程序白屏問題進行一番探究。javascript
從小程序官方開發者文檔得知,微信小程序運行在三端:iOS(iPhone/iPad)、Android和用於調試的開發者工具。三端的腳本執行環境以及用於渲染非原生組件的環境是各不相同的[1]:html
下面說說WKWebView、Mobile Chrome 53/5七、Mobile Chrome 53是什麼。前端
在Apple公司的開發者文檔網站上,有對WKWebView進行介紹,簡單來講,WKWebView是一個爲app內置瀏覽器渲染交互式網頁內容的組件,用於替換老版本的UIWebView組件[2]。不論是UIWebView,仍是WKWebView,它們都屬於IOS WebView。咱們能夠把WebView理解爲手機操做系統的一個系統級的組件。不論是手機內置的瀏覽器,仍是其餘app,好比微信等,只要你想呈現交互式的網頁內容,均可以調用WebView去完成這件事情。Android WebView亦是如此[3]。java
如今咱們能夠把WKWebView稱爲IOS端的WebView,那麼Android端的Mobile Chrome 53/57,或者Mobile Chrome 53又是什麼,這兩個跟WebView又是什麼關係呢? 咱們能夠把Mobile Chrome 53/57理解爲Chrome for Android 537版本,這裏的537是指Chrome的排版引擎(layout engine)採用的WebKit內核版本,具體參考Google Chrome version history[4]。須要指出的是,53/57是否是就是537,這裏存疑,沒有查到有效的參考資料,可是這個對咱們的研究應該沒有什麼影響,能夠不予考慮。到這裏,又引入了兩個概念:layout engine、WebKit內核。接下來簡單介紹一下layout engine和WebKit內核。android
咱們都知道瀏覽器有兩個重要的引擎:渲染引擎(rendering engine,也稱layout engine,即上面提到的排版引擎,後續爲了方便,統一描述爲渲染引擎)和JS引擎。其中渲染引擎負責解析網頁內容,計算顯示方式,輸出至顯示設備。JS引擎則負責解析JavaScript語言,實現網頁的動態交互效果。最開始時渲染引擎和JS引擎並無區分的很明確,後來JS引擎愈來愈獨立,內核就傾向於只指渲染引擎,即瀏覽器內核就是該瀏覽器採用的渲染引擎,主要參考X5內核調研報告[5]。在後續的討論中,瀏覽器內核就單指渲染引擎。web
那WebKit內核又是什麼?這個不得不追溯WebKit的歷史了。1998,自由軟件社區KDE開發了HTML排版引擎KHTML和JavaScript解析引擎KJS,也就是現代瀏覽器兩個重要的引擎。Apple公司的開發者Don Melton於2001年在KDE的基礎之上開始了WebKit項目。剛開始時,WebKit僅爲KDE的復刻,咱們能夠理解爲WebKit是KDE基礎上fork出來的分支。後來,在WebKit項目中,KHTML被命名爲WebCore,KJS被命名爲JavaScriptCore,主要參考維基百科[6]。至此,咱們能夠回答,至少針對Apple的產品來講,瀏覽器內核就是WebKit,即渲染引擎採用的是WebKit內核。小程序
webkit項目是Apple公司發展自家瀏覽器啓動的項目。Google公司在發展Chrome瀏覽器也成立了Chromium項目。在Chromium項目中,JavaScript解析引擎採用Google本身開發的大名鼎鼎的V8引擎,渲染引擎採用的是WebKit內核。到2013年7月份,Chromium項目將渲染引擎替換爲Blink引擎,並在Chrome28及後續的版本上採用[4][7]。Blink引擎是Google在WebKit項目中的WebCore基礎上fork出來的一個分支[8][9]。咱們能夠用一幅圖把KDE、WebKit和Chromium串聯起來:微信小程序
如今,咱們再回過頭來看一下Mobile Chrome 53/57,或者Mobile Chrome 53,其實它的內核仍是從WebKit上演化而來。繞了這麼遠,只爲一句話:小程序就是運行在WebView之上。那麼咱們的初衷,研究小程序白屏問題,其實就是在探究WebView白屏問題。若是要更詳細一點,那就是WKWebview、Android WebView白屏的緣由。瀏覽器
關於WKWebview白屏,網上羅列的常見緣由大體有如下幾種:微信
針對緣由3,解決的方案是判斷IOS系統版本,小於8.2的使用UIWebView。若是站在小程序開發者的角度,這個跟咱們好像沒有關係。小程序是個平臺,咱們在這個平臺上開發咱們的小程序應用,若是小程序也有這個問題,那隻能由小程序團隊去解決這件事情。還有,好比緣由4,咱們該嵌套仍是得嵌套,有問題也是小程序團隊去解決。至於緣由2,若是是小程序原生開發的話,頁面間的跳轉URL包含中文也是能正常跳轉的,這個應該是小程序內部兼容了。可是緣由1,這個跟咱們就有很大的關係了,好比咱們定義了大量的變量,使用完了卻沒有釋放,那麼這部份內存在小程序銷燬以前會被一直佔用。再好比咱們在某一刻操做了某個比較大的變量,可能在短期內,內存使用量也會飆升。一樣的,對於致使Android WebView白屏的問題,絕大部分也只能由小程序團隊去解決。
這樣一來,從開發小程序應用的前端角度來講,咱們可以把握的是儘可能避免因爲內存使用緊張致使的部分WebView被回收而出現的白屏問題。至此,咱們研究的小程序白屏問題,能夠轉向對小程序內存優化的研究。
下面總結一下平時開發過程當中可能會致使內存警告的操做:
使用大圖片和長列表圖片。根據小程序團隊分析過的大部分案例,大圖片和長列表圖片的使用,都會引發WKWebview被回收[10]。其中長列表頁圖片是指頁面包含數目較大的列表,每一個列表裏面又引用了圖片。
隨意定義變量,因爲小程序的機制而又沒有獲得釋放。如下四種場景下定義的變量,即便離開當前頁面,變量也不會被回收:
定義在Page構造器外層的全局變量。
定義在data內部的數據。
定義在Page內部,類data數據。
掛載到getApp().globalData上的數據。
假如咱們在testvar頁面定義了上述變量,由testvar經過navigateTo跳轉到下一個頁面otherpage,在頁面otherpage裏面咱們能夠經過getCurrentPages()獲取頁面testvar的引用,進而獲取裏面的變量。經過navigateTo打開新頁面,上一個頁面進入頁面棧,而且該頁面只是hide,並非unload[11]。小程序框架的頁面棧最多可支持10層頁面。設想一下,那些具備複雜交互的頁面,每層頁面都附帶了衆多的數據,甚至包含不少圖片,再考慮多層頁面並存的問題,那內存使用量將是很可觀的。在頁面棧裏面的頁面unload以前,都會形成持續的內存佔用。
短期內大數據操做。假設在某個時間點,咱們須要對接口返回的大量數據進行操做,可能會形成瞬時的內存佔用。
列表數據的持續累加,致使某個數據異常大。設想一下,假如咱們的列表頁有不少條數據,每通過一次分頁請求,咱們就把新的數據concat到已有的數據之上,長此以往,這條數據可能會變成巨無霸,逐漸侵蝕咱們的內存。
所幸的是,上述這些可能形成內存大量佔用的操做,咱們是能夠避免或者優化的。
但願你們進行批評和指正!
參考文獻: [1]: developers.weixin.qq.com/miniprogram… [2]: developer.apple.com/documentati… [3]: developer.android.com/reference/a… [4]: en.wikipedia.org/wiki/Google… [5]: juejin.im/post/5a3522… [6]: zh.wikipedia.org/wiki/WebKit [7]: zh.wikipedia.org/wiki/Google… [8]: zh.wikipedia.org/wiki/Chromi… [9]: zh.wikipedia.org/wiki/Blink [10]:developers.weixin.qq.com/miniprogram… [11]: developers.weixin.qq.com/miniprogram…