小程式原生開發有不少槽點:
- 原生wxml開發對Node、預編譯器、webpack支援不好,影響開發效率和工程構建流程。所以大公司都會用框架開發
- 微信定義的這套語法,wxml、wxs,以及wx:if等語法,私有化太強。不如正經學vue,學會了全端通用,而不是隻為微信小程式
- vue生態裡有太多周邊工具,可以提高開發效率,比如ide、校驗器、三方庫。。。而微信的開發者工具和專業編輯器相比實在不好用,個性化設定也非常少
作為前端工程師,除了微信小程式,還要開發web、其他小程式甚至App,人們不喜歡來回切換開發工具和變更語法思考方式。
uni-app自然可以解決這些問題,但開發者又經常有些顧慮:
- 怕使用uni-app後,微信小程式裡有的功能無法實現,受制於uni-app的更新
- 怕效能不如原生WXML
- 怕框架不成熟,跳到坑裡
- 擔心社群生態不完善
本文從開發者關心的功能、效能、學習門檻、開發體驗、生態、可擴充套件性等維度,逐個分析對比,給予說明。
1.功能實現
開發者最常問的問題:如果小程式迭代升級,新增了一批API,但uni-app
框架未及時更新,該怎麼辦?
其實這是誤解,uni-app
不限制底層API 呼叫;在小程式端,uni-app
支援直接編寫微信原生程式碼。
類比傳統web開發,如果vue、react等框架的使用,造成開發者無法操作瀏覽器提供的所有api,那這樣的框架肯定是不成熟的。小程式開發也一樣,uni-app
框架中,同樣可呼叫微信提供的所有原生程式碼。
故如果存在某些API(平臺特有或新增API),uni-app
尚未封裝,開發者可直接在uni-app
中編寫微信原生API,即wx.開頭的各種API。
舉個例子,目前uni-app
雖然尚未封裝跨平臺的廣告(ad)元件,但開發者在小程式端依然可以使用微信<ad>
元件來展現廣告,程式碼示例如下:
<view>
<view class="title">微信官方banner廣告</view>
<view style="min-height: 50px;">
<!-- uni-app尚未封裝,但可直接使用微信原生的ad元件-->
<ad unit-id="adunit-01b7axxxbf53d74e"></ad>
</view>
<view class="title">微信官方視訊廣告</view>
<view style="min-height: 50px;">
<!-- uni-app尚未封裝,但可直接使用微信原生的ad元件-->
<ad unit-id="adunit-9f340xxx64533" ad-type="video" ad-theme="white"></ad>
</view>
</view>
複製程式碼
小程式端執行效果如下:
包括微信小程式自定義元件、WXS、雲開發這些複雜用法,在uni-app裡一樣全面支援。
所以,結論是:使用uni-app
框架開發,在功能上和原生小程式開發沒有區別,不會有任何限制。
2. 效能體驗
開發者常問的第二個問題:三方框架,內部大多做了層層封裝,這些封裝是否會增加執行負載,導致效能下降?
同樣是多慮了,uni-app
不會導致效能下載,甚至對很多環節做了自動優化,很多場景下效能體驗比微信原生開發更好。
類似使用vue.js開發web,不但不會造成效能比原生js差,反而由於虛擬dom和差量更新技術的運用,在大多數場景下,比開發者手動寫程式碼操作dom的效能還好。
小程式中需要頻繁的寫setData程式碼來更新資料,這裡很重要的就是差量資料更新。如果不做差量,程式碼效能不好,如果每處邏輯都判斷差量資料更新,那程式碼寫起來太麻煩了。
使用uni-app
,底層自動差量資料更新,簡單而高效能。
我們從優化理論、實測資料兩個維度來仔細說明。
2.1 理論:框架優化方案
為提高效能體驗,小程式從架構設計層面做了很多工作:
- 邏輯層、檢視層分離,避免JS運算阻塞檢視渲染
- 單獨定義元件標籤(wxml),減少DOM複雜度
- 精簡樣式(wxss),提升渲染效能
- 複雜元件原生化(video/map等),解決web元件的功能/體驗缺失
通過這些規範約束,大幅提升了小程式的整體效能體驗,但依然存在不少效能坑點,其中以setData
最為頻繁普遍。
這裡引用微信官方的描述,簡單介紹一下setData
背後的工作原理:
小程式的檢視層目前使用 WebView 作為渲染載體,而邏輯層是由獨立的 JavascriptCore 作為執行環境。在架構上,WebView 和 JavascriptCore 都是獨立的模組,並不具備資料直接共享的通道。當前,檢視層和邏輯層的資料傳輸,實際上通過兩邊提供的 evaluateJavascript 所實現。
為簡化開發,微信將evaluateJavascript
呼叫封裝成了setData
JS方法,實現檢視層和邏輯層的資料傳輸,資料流示意圖如下:
setData
的執行會受到很多因素的影響,setData
每次傳遞資料量過大或頻繁被呼叫(見微信官方介紹),都可能引發效能體驗問題。
幸運的是,uni-app
在這兩個方面都有優化。
2.1.1 減少 setData 傳遞資料量
假設當前頁面有一個列表(初始值為a,b,c,d
),現在要向列表後追加4個新列表項(e,f,g,h
),我們分別以微信原生、uni-app 兩種模式編寫程式碼。
小程式原生程式碼:
page({
data:{
list:['a','b','c','d']
},
change:function(){
let newData = ['e','f','g','h'];
this.data.list.push(...newData);
this.setData({
list:this.data.list
})
}
})
複製程式碼
如上微信原生程式碼,change
方法執行時,會將list
中的a,b,c,d,e,f,g,h
8個列表項通過setData
全部傳輸過去。
uni-app 程式碼:
export default{
data(){
return {
list:['a','b','c','d']
}
},
methods:{
change:function(){
let newData = ['e','f','g','h'];
this.list.push(...newData)
}
}
}
複製程式碼
如上uni-app
程式碼,change
方法執行時,僅會將list
中的e,f,g,h
4個新增列表項傳輸過去,實現了setData
傳輸量的極簡化。
uni-app
借鑑了 westore JSON Diff庫,在呼叫setData
之前,會先比對歷史資料,精確、高效計算出有變化的差量資料,然後再呼叫setData
,僅傳輸變化的資料,這樣就實現 setData 傳遞資料量的最小化,大幅提高通訊效能。
Tips:也許有些同學對傳遞資料從a,b,c,d,e,f,g,h
8個列表項優化為e,f,g,h
4個列表項,不以為然,但我們提醒,不要小看這個機制,上述只是demo示例。
- 在實際列表場景中,每個列表項可能包含縮圖、標題、摘要、時間等各種資訊,每個列表項資料都會更大(假設為1k);
- 假設當前頁面有20個列表項,連續上拉4次後,頁面變成100條記錄;如果再次上拉,頁面變成120條記錄時,情況會有不同
- 上述微信原生的方式,將120條記錄資料(120k)全部傳輸過去
- 上述 uni-app 模式,僅會將新增的20條(101 ~ 120)記錄資料(20k)傳輸過去,資料量是原生方式的1/6!
- 當頁面列表項資料越多,這個差別就越大,頁面有200條記錄時,uni-app傳遞資料量會變成微信原生資料傳遞量的1/10!
2.1.2 減少 setData 呼叫頻次
假設我們有更改多個變數值的需求,我們分別以微信原生、uni-app 兩種模式編寫程式碼。
小程式原生程式碼:
change:function(){
this.setData({a:1});
this.setData({b:2});
this.setData({c:3});
this.setData({d:4});
}
複製程式碼
如上四次呼叫setData
,就會引發4次邏輯層、檢視層資料通訊
uni-app 程式碼:
change:function(){
this.a = 1;
this.b = 2;
this.c = 3;
this.d = 4;
}
複製程式碼
如上uni-app
的程式碼,最後會被合併成{"a":1,"b":2,"c":3,"d":4}
一條資料,然後僅呼叫一次setData
完成所有資料傳遞,大幅降低了setData
的呼叫頻次。
uni-app
之所以有這樣的優勢,是因為 uni-app 基於 Vue Runtime 深度定製實現,並藉助了 Vue 的 nextTick 機制。
2.2 實測:效能對比資料
有了如上的理論分析,我們接著進行真機實測,用資料來對比。
測試模型如下:
-
開發內容:開發一個仿微博小程式首頁的複雜長列表,支援下拉重新整理、上拉翻頁、點贊。仿微博的列表是一個包含很多元件的列表,這種複雜列表對效能的壓力更大,很適合做效能測試。
-
介面如下:
-
開發版本:使用微信原生、uni-app分別開發兩套程式碼,uni-app使用
cli
方式預設安裝。 -
測試程式碼開源(Github倉庫地址:https://github.com/dcloudio/test-framework), Tips:若有同學覺得測試程式碼寫法欠妥,歡迎提交 PR 或 Issus,本專案下還有其它框架的測試程式碼,開發者可忽略
-
測試機型:紅米 Redmi 6 Pro、MIUI 10.2.2.0 穩定版(最新版)、微信版本 7.0.3(最新版)
-
測試環境:每個框架開始測試前,殺掉各App程式、清空記憶體,保證測試機環境基本一致;每次從本地讀取靜態資料,遮蔽網路差異。
從觸發上拉載入到資料更新、頁面渲染完成,需要準確計時。人眼視覺計時肯定不行,我們採用程式埋點的方式,制定瞭如下計時時機:
- 計時開始時機:互動事件觸發,框架賦值之前,如:上拉載入(onReachBottom)函式開頭
- 計時結束時機:頁面渲染完畢(微信setData回撥函式開頭)
Tips:setData
回撥函式開頭可認為是頁面渲染完成的時間,是因為微信setData
定義如下(微信規範):
欄位 | 型別 | 必填 | 描述 |
---|---|---|---|
data | Object | 是 | 這次要改變的資料 |
callback | Function | 否 | setData引起的介面更新渲染完畢後的回撥函式 |
測試方式:從頁面空列表開始,通過程式自動觸發上拉載入,每次新增20條列表,記錄單次耗時;固定間隔連續觸發 N 次上拉載入,使得頁面達到 20*N 條列表,計算這 N 次觸發上拉到渲染完成的平均耗時。
測試結果如下:
列表條數 | 微信原生 | uni-app |
---|---|---|
200 | 770 | 641 |
400 | 876 | 741 |
600 | 1111 | 910 |
800 | 1406 | 1113 |
1000 | 1690 | 1321 |
說明:以400條微博列表為例,從頁面空列表開始,每隔1秒觸發一次上拉載入(新增20條微博),記錄單次耗時,觸發20次後停止(頁面達到400條微博),計算這20次的平均耗時,結果微信原生在這20次 觸發上拉 -> 渲染完成
的平均耗時為876毫秒,uni-app
是741毫秒。
這個資料,可能違反了很多人的直覺,uni-app 的效能竟然比微信原生還好!
不必疑惑,這就是上面理論分析章節中,減少setData
傳遞資料量優化方案的結果;微信原生每次傳遞全量資料,而uni-app
在呼叫setData
之前會自動做diff
計算,每次僅傳遞變動的資料。
開發者使用微信原生框架,完全可以自己優化,精簡傳遞資料,比如修改如下:
data: {
listData: []
},
onReachBottom() { //上拉載入
// 通過長度獲取下一次渲染的索引
let index = this.data.listData.length;
let newData = {}; //新變更資料
Api.getNews().forEach((item) => {
newData['listData[' + (index++) + ']'] = item //賦值,索引遞增
})
this.setData(newData) //增量資料,傳送資料到檢視層
}
複製程式碼
經過如上優化修改後,再次測試,微信原生框架效能資料如下:
元件數量 | 微信原生框架(優化前) | 微信原生框架(優化後) | uni-app |
---|---|---|---|
200 | 770 | 572 | 641 |
400 | 876 | 688 | 741 |
600 | 1111 | 855 | 910 |
800 | 1406 | 1055 | 1113 |
1000 | 1690 | 1260 | 1321 |
從測試結果可看出,經過開發者手動優化,微信原生框架可達到更好的效能,但 uni-app
相比微信原生,效能差距並不大。
但原生開發需要開發者熟悉小程式通訊機制,有意識的去編寫程式碼,精簡資料;uni-app自動處理,自然是更省心。
這個結果,和web開發類似,web開發也有原生js開發、vue、react框架等情況。如果不做特殊優化,原生js寫的網頁,效能經常還不如vue、react框架的效能。
也恰恰是因為Vue
、react
框架的優秀,效能好,開發體驗好,所以原生js開發已經逐漸減少使用了。
通過本章節效能優化的理論分析及資料實測,我們可以輸出這麼個結論:
- uni-app 不會增加小程式執行負載,不會拉低執行效能
- uni-app 自動處理了很多效能優化點,對不懂效能調優或不熟悉小程式架構設計的開發者,更友好,更省心
3.社群生態
3.1 周邊輪子
小程式是脫離web自造生態,很多web生態中輪子無法使用。
微信小程式還是有周邊生態的,而其他幾家小程式平臺的生態基本沒建起來。
uni-app
的周邊生態非常豐富,在外掛市場有近800個外掛,詳見 ext.dcloud.net.cn。
首先uni-app
相容小程式的生態,各種自定義元件均可直接引入使用。在此基礎上,uni-app
的外掛市場,有更多vue元件,同時可跨多端使用,並且效能優秀。
這使得uni-app
的生態成為最豐富的小程式開發生態。
比如富文字解析、圖表等元件,uni-app
的外掛效能均超過了wxparse、wx-echart等微信小程式元件。
如果開發者需要豐富和高效能的元件,更應該使用uni-app
,而不是原生小程式開發。
3.2 活躍的QQ/微信群和論壇
uni-app
官方有 70 個開發者QQ/微信交流群(大多2千人群,近10萬開發者),三方群更多。
問答社群,每天有數百篇帖子。活躍度與微信小程式官方論壇相同,遠超過其他小程式官方論壇。
uni-app
三方培訓活躍,騰訊課堂官方都為uni-app製作了課程,各種培訓網站到處可見免費或收費的uni-app培訓視訊教程。
4.學習門檻、開發體驗
首先微信原生的開發語法,既像React
,又像Vue
,有點不倫不類,對於開發者來說,等於又要學習一套新的語法,大幅提升了學習成本,這一直被大家所詬病。
uni-app
則對開發者更為友好,簡單來說是 vue的語法 + 小程式的api。
它遵循Vue.js
語法規範,元件和API遵循微信小程式命名
,這些都屬於通用技術棧,學習它們是前端必備技能,uni-app
沒有太多額外學習成本。
有一定 Vue.js 和微信小程式開發經驗的開發者可快速上手 uni-app
。
沒學過vue的同學,也不用掌握vue的全部,只需瞭解vue基礎語法、資料繫結、列表渲染、元件等,其他如路由、loader、cli、node.js、webpack並不需要學。
因為HBuilderX工具搭配uni-app
可以免終端開發,視覺化建立專案、視覺化安裝元件和擴充套件編譯器,也就是uni-app
的學習門檻,比web開發的vue.js還低。
開發體驗層面,微信原生開發相比uni-app
有較大差距,主要體現在:
- 更為強大的元件化開發能力:vue的元件開發比小程式自定義元件開發的體驗要好很多
- 應用狀態管理:uni-app支援vuex
- 使用 Sass 等 CSS 前處理器
- 完整的 ES Next 語法支援
- 自定義構建策略
開發工具維度,差距更大:
- 微信開發者工具被吐槽無數
uni-app
的出品公司,同時也是HBuilder的出品公司,DCloud.io。HBuilder/HBuilderX系列是四大主流前端開發工具(可對比百度指數),其為uni-app
做了很多優化,故uni-app
的開發效率、易用性非微信原生開發可及。
這裡可以輸出一個結論:如果你需要工程化能力,那就直接忘了微信原生開發吧。
5.未來擴充套件性
雖然當前產品僅要求釋出到微信小程式,但若有一天,老闆和外來的一個和尚喝完咖啡,轉身就要求覆蓋阿里、百度、位元組跳動等各家小程式平臺,此時程式設計師該怎麼辦?
難道真的每個平臺到處搬磚嗎?
此時,uni-ap
的跨端功能將成為程式設計師的自救神器,基於uni-app
開發的小程式,無需修改,即可同時釋出到多家小程式,甚至App、H5平臺。這不是夢想,而是現實。大家可依次掃描如下8個二維碼,親自體驗最全面的跨平臺效果!。
6.結語
uni-app | 微信 | |
---|---|---|
功能 | 相同 | 相同 |
效能 | 常規場景更優 | 需要自己編寫複雜程式碼才能提高效能 |
社群生態 | 豐富,更多高效能元件 | 豐富 |
開發體驗 | 純vue體驗,高效、統一;工程化能力強 | 語法私有化;工程化能力弱 |
多端能力 | 同時支援H5、多家小程式、跨平臺App | 只能用於微信小程式 |
結論:只開發微信小程式,也應該使用uni-app