uni app性能優化建議

運行原理

邏輯層和視圖層分離,且非H5端通信有折損

uni-app 在非H5端運行時,從架構上分爲邏輯層和視圖層兩個部分。邏輯層負責執行業務邏輯,也就是運行js代碼,視圖層負責頁面渲染。

雖然開發者在一個vue頁面裏寫js和css,但其實,編譯時就已經將它們拆分了。

邏輯層詳解

邏輯層是運行在一個獨立的jscore裏的,它不依賴於本機的webview,所以一方面它沒有瀏覽器兼容問題,可以在Android4.4上跑es6代碼,另一方面,它無法運行window、document、navigator、localstorage等瀏覽器專用的js API。

jscore 就是一個標準js引擎,標準js是可以正常運行的,比如if、for、各種字符串、日期處理等。js和瀏覽器的區別要注意區分開來。

  • 所謂瀏覽器的js引擎,就是jscore或v8的基礎上新增了一批瀏覽器專用API,比如dom;
  • node.js引擎,則是v8基礎上補充一些電腦專用API,比如本地io;
  • 那麼uni-app的App端和小程序端的js引擎,其實是在jscore上補充了一批手機端常用的JS API,比如掃碼。

在這裏插入圖片描述

視圖層詳解

h5和小程序平臺,以及app-vue,視圖層是webview。而app-nvue的視圖層是基於weex改造的原生視圖。

在iOS上,所有人都只能使用iOS提供的webview。它有一定的瀏覽器兼容問題,iOS版本不同,它的表現有細微差異。

Android上小程序大多自帶了一個幾十M的chromium webview,而App端沒辦法帶這麼大體積的三方包,所以App端使用了Android system webview,而系統webview跟隨手機不同而有差異。

所以uni-app的js基本沒有不同手機的兼容問題(因爲js引擎自帶了),而視圖層的css,在app-vue上會有手機瀏覽器的css兼容問題。所以在app-vue的場景中儘量不要使用太新的css語法,除非你不打算支持低端機。

邏輯層和視圖層分離的利與弊

邏輯層和視圖層分離,好處是js運算不卡渲染,最簡單直接的感受就是:窗體動畫穩。

如果開發者使用過App,應該有概念,webview新窗體一邊做進入動畫,一邊自身渲染,很容易卡動畫。而uni-app則無需寫預載代碼,新窗體渲染快且動畫穩定。

但是兩層分離也帶來一個壞處,這兩層互相通信,其實是有損耗的。

iOS還好,但Android低端機上,每次通信都要耗時幾十毫秒。平時看不出來影響,但有幾個場景表現明顯。

  1. 連續高幀率繪製canvas動畫,會發現還不如webview內部繪製流程
  2. 視圖層滾動、跟手操作,不停反饋給邏輯層,js再處理邏輯並通知視圖層做對應更新。此時會發現交互不跟手或卡

不管app-vue/小程序,還是app-nvue,都有相同的問題。

解決這類問題,在webview渲染和原生渲染引用了不同的做法。

  • webview渲染的視圖層

在app-vue和微信小程序上,提供了一種運行於視圖層的專屬js,微信叫做wxs,uni-app也沿用了這個名稱。

微信裏對wxs限制較多,只能實現有限的功能,app端(尤其是v3編譯器下)則沒有限制。

wxs中可以監聽手勢,以uni ui的swiperAction組件爲例,手指拖動,側邊的列表菜單項要跟手滑出,此時就需要使用wxs才能實現流暢效果。

至於canvas動畫,微信的canvas是原生的,無法運用wxs操作,且一樣有通信折損,所以繪製動畫的性能不佳。而uni-app的app-vue的canvas是webview的,並且支持wxs操作,開發者可以在普通js中傳遞數據和指令給wxs,在wxs裏繪製動畫,將不再有通信折損,實現更流暢的效果(app端需v3編譯器)

  • 原生渲染的視圖層

在app-nvue裏,折損一樣存在。包括react native也有這個問題。weex發明了一套bindingx機制,可以在js裏傳一個表達式給原生,由原生解析後根據指令操作視圖層,這個技術在uni-app裏也可以使用。

bindingx作爲一種表達式,它的功能不及js強大,但基本的手勢監聽、動畫還是可以實現的,比如uni ui的swiperAction組件在app-nvue下運行時會自動啓用bindingx,以實現流暢跟手。

app-vue和小程序的數據更新,分頁面級和組件級

對於複雜頁面,更新某個區域的數據時,需要把這個區域做成組件,這樣更新數據時就只更新這個組件,否則會整個頁面的數據更新,造成點擊延遲卡頓。 這就是自定義組件編譯模式的特點。

比如微博長列表頁面,點擊一個點贊圖標,贊數要立即+1,此時這個點贊按鈕一定要做成組件。否則這個+1會引發頁面級所有數據的更新。

app-nvue和h5不存在此問題。造成差異的原因是小程序目前只提供了組件差量更新的機制,不能自動計算所有頁面差量。

優化建議

使用自定義組件模式

使用自定義組件模式,在manifest中配置自定義組件模式(HBuilderX1.9起新建項目默認即爲自定義組件模式)。

在複雜頁面中,頁面中嵌套大量組件,如果是非自定義組件模式,更新一個組件會導致整個頁面數據更新。而自定義組件模式則可以單獨更新一個組件的數據。

在App端,除了上述好處,自定義組件模式還新增了一個獨立的js引擎,加快啓動速度、減少js阻塞。

之前的非自定義組件模式已經不再推薦,如果你的應用還是非自定義組模式,請儘快升級。

避免使用大圖

頁面中若大量使用大圖資源,會造成頁面切換的卡頓,導致系統內存升高,甚至白屏崩潰。

尤其是不要把多張大圖縮小後顯示在一個屏幕內,比如上傳圖片前選了數張幾M體積的照片,然後縮小在一個屏幕中展示多張幾M的大圖,非常容易白屏崩潰。

優化數據更新

uni-app 中,定義在 data 裏面的數據每次變化時都會通知視圖層重新渲染頁面。 所以如果不是視圖所需要的變量,可以不定義在 data 中,可在外部定義變量或直接掛載在vue實例上,以避免造成資源浪費。

長列表

  • 長列表中如果每個item有一個點贊按鈕,點擊後點贊數字+1,此時點贊組件必須是一個單獨引用的組件,才能做到差量數據更新。否則會造成整個列表數據重載。(要求自定義組件模式)
  • 長列表中每個item並不一定需要做成組件,取決於你的業務中是否需要差量更新某一行item的數據,如沒有此類需求則不應該引入大量組件。(點擊item後背景變色,屬於css調整,沒有更新data數據和渲染,不涉及這個問題)
  • app端nvue的長列表應該使用list組件,有自動的渲染資源回收機制。vue頁面使用頁面滾動的性能,好於使用scroll-view的區域滾動。uni ui封裝了uList組件,強烈推薦開發者使用,避免自己寫的不好產生性能問題。
  • 如需要左右滑動的長列表,請在HBuilderX新建uni-app項目選新聞模板,那是一個標杆實現。自己用swiper和scroll-view做很容易引發性能問題。
減少一次性渲染的節點數量

頁面初始化時,邏輯層如果一次性向視圖層傳遞很大的數據,使視圖層一次性渲染大量節點,可能造成通訊變慢、頁面切換卡頓,所以建議以局部更新頁面的方式渲染頁面。如:服務端返回100條數據,可進行分批加載,一次加載50條,500ms 後進行下一次加載。

減少節點嵌套層級

深層嵌套的節點在頁面初始化構建時往往需要更多的內存佔用,並且在遍歷節點時也會更慢些,所以建議減少深層的節點嵌套。

避免視圖層和邏輯層頻繁進行通訊

  • 減少 scroll-view 組件的 scroll 事件監聽,當監聽 scroll-view
    的滾動事件時,視圖層會頻繁的向邏輯層發送數據;

  • 監聽 scroll-view 組件的滾動事件時,不要實時的改變 scroll-top/scroll-left 屬性,因爲監聽滾動時,視圖層向邏輯層通訊,改變 scroll-top/scroll-left 時,邏輯層又向視圖層通訊,這樣就可能造成通訊卡頓。

  • 注意 onPageScroll 的使用,onPageScroll 進行監聽時,視圖層會頻繁的向邏輯層發送數據;

  • 多使用css動畫,而不是通過js的定時器操作界面做動畫

  • 如果是canvas裏做跟手操作,建議使用web-view組件。web-view裏的頁面沒有邏輯層和視圖層分離的概念,自然也不會有通信折損。

優化頁面切換動畫

  • 頁面初始化時若存在大量圖片或原生組件渲染和大量數據通訊,會發生新頁面渲染和窗體進入動畫搶資源,造成頁面切換卡頓、掉幀。建議延時100ms~300ms渲染圖片或複雜原生組件,分批進行數據通訊,以減少一次性渲染的節點數量。

  • App端動畫效果可以自定義。popin/popout的雙窗體聯動擠壓動畫效果對資源的消耗更大,如果動畫期間頁面裏在執行耗時的js,可能會造成動畫掉幀。此時可以使用消耗資源更小的動畫效果,比如slide-in-right/slide-out-right。

優化背景色閃白

  • 如果頁面背景是深色,在vue頁面中可能會發生新窗體剛開始動畫時是灰白色背景,動畫結束時才變爲深色背景,造成閃屏。這是因爲webview的背景生效太慢的問題。此時需將樣式寫在
    App.vue 裏,可以加速頁面樣式渲染速度。App.vue 裏面的樣式是全局樣式,每次新開頁面會優先加載 App.vue
    裏面的樣式,然後加載普通 vue 頁面的樣式。

  • 還可以在pages.json的globalStyle->style->app-plus->background下配置全局背景色

"style": {  
  "app-plus": {  
      "background":"#000000"
  }  
}
  • 另外nvue頁面不存在此問題,也可以更改爲nvue頁面。

使用nvue代替vue

在 App 端 uni-app 的 nvue 頁面可是基於 weex 定製的原生渲染引擎,實現了頁面原生渲染能力、提高了頁面流暢性。若對頁面性能要求較高可以使用此方式開發,詳見:nvue

優化啓動速度

  • 工程代碼越多,包括背景圖和本地字體文件越大,對App的啓動速度有影響,應注意控制體積。組件引用的前景圖不影響性能。

  • App端的 splash 關閉有白屏檢測機制,如果首頁一直白屏或首頁本身就是一個空的中轉頁面,可能會造成 splash 10秒才關閉,可參考此文解決https://ask.dcloud.net.cn/article/35565

  • App端使用自定義組件模式時啓動速度更快,首頁爲nvue頁面時啓動速度更快

  • App設置爲純nvue項目(manifest裏設置app-plus下的renderer:“native”),這種項目的啓動速度更快,2秒即可完成啓動。因爲它整個應用都使用原生渲染,不加載基於webview的那套框架。

優化包體積

  • uni-app發行到小程序時,自帶引擎只有幾十K,主要是一個定製過的vue.js核心庫。如果使用了es6轉es5、css對齊的功能,可能會增大代碼體積,可以配置這些編譯功能是否開啓。
  • uni-app的H5端,自帶了vue.js、vue-router及部分es6 polyfill庫,這部分的體積gzip後只有92k,和web開發使用vue基本一致。而內置組件ui庫(如picker、switch等)、小程序的對齊js api等,相當於一個完善的大型ui庫。但大多數應用不會用到所有內置組件和API。由此uni-app提供了搖樹優化機制,未搖樹優化前的uni-app整體包體積約500k,服務器部署gzip後162k。開啓搖樹優化需在manifest配置,詳情
  • uni-app的App端,因爲自帶了一個獨立v8引擎和小程序框架,所以比HTML5Plus或mui等普通hybrid的App引擎體積要大。Android基礎引擎約15M。App還提供了擴展模塊,比如地圖、藍牙等,打包時如不需要這些模塊,可以裁剪掉,以縮小發行包體積。在 manifest.json-App模塊權限 裏可以選擇。
  • App端支持如果選擇純nvue項目(manifest裏設置app-plus下的renderer:“native”),包體積可以進一步減少2M左右。
  • uni-app的App端默認包含arm32和x86兩個cpu的支持so庫。這會增大包體積。如果你在意體積控制,可以在manifest裏去掉x86 cpu的支持(manifest可視化界面-App其他設置裏選擇cpu),這可以減少包體積到9M。但代價是不支持intel的cpu了。一般手機都是arm的,僅個別少見的Android pad使用x86 cpu。另外as的模擬器裏如果選擇x86時也無法運行這種apk。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章