谜之wxs,uni-app如何用它大幅提升性能
小程序里有幾個謎一樣的存在,微信的WXS、支付寶的SJS、百度的Filter。
很多開發(fā)者都不明白為什么要造這種語言腳本的輪子出來,甚至很多開發(fā)者根本不知道它們的存在。
其實(shí)幾大小程序平臺創(chuàng)造它們,都是為了解決性能問題,但不得不吐槽下,設(shè)計的實(shí)在是很難用,文檔也語焉不詳。
uni-app支持將WXS、SJS、Filter編譯到這3家小程序平臺,同時還在App和H5實(shí)現(xiàn)了WXS的解析。為什么做這些事?也是為了性能。
uni-ui庫新版中的swiperaction組件,就是列表項(xiàng)向左滑動時拉出幾個擠壓式聯(lián)動的菜單按鈕,這種流暢的跟手動畫,正是借助于WXS機(jī)制實(shí)現(xiàn)的。
微信為何要創(chuàng)造WXS
WXS(WeiXin Script)是微信創(chuàng)造的一套腳本語言,它的官方說法是:“WXS 與 JavaScript 是不同的語言,有自己的語法,并不和 JavaScript 一致”。
那微信為何要脫離 JavaScript ,單獨(dú)創(chuàng)造一套語言呢?這要從微信小程序的底層邏輯(運(yùn)行環(huán)境)講起。
小程序的運(yùn)行環(huán)境分為邏輯層和視圖層,分別由2個線程管理,其中:
- WXML 模板和 WXSS 樣式工作在視圖層,界面使用 WebView 進(jìn)行渲染
- JavaScript代碼工作在邏輯層,運(yùn)行在JsCore或v8里
小程序在視圖層與邏輯層兩個線程間提供了數(shù)據(jù)傳輸和事件系統(tǒng)。這樣的分離設(shè)計,帶來了顯而易見的好處:
- 邏輯和視圖分離,即使業(yè)務(wù)邏輯計算非常繁忙,也不會阻塞渲染和用戶在視圖層上的交互
但同時也帶來了明顯的壞處:
- 視圖層(webview)中不能運(yùn)行JS,而邏輯層JS又無法直接修改頁面DOM,數(shù)據(jù)更新及事件系統(tǒng)只能靠線程間通訊,但跨線程通信的成本極高,特別是需要頻繁通信的場景
什么是需要頻繁通訊的場景?最典型的例子就是用戶持續(xù)交互的情況,比如觸摸、滾動等。我們以側(cè)滑菜單為例,假設(shè)在頁面上滑動A元素,要求B元素跟隨移動,一次滑動操作(touchmove)的響應(yīng)過程如下:
一次 touchmove 的響應(yīng)需要經(jīng)過 視圖層、Native、邏輯層三者之間2個完整來回的通信,通信的耗時開銷較大,用戶的交互就會出現(xiàn)延時卡頓的情況。
除了滾動、拖動交互外,在for循環(huán)里對數(shù)據(jù)做格式修改,也會造成邏輯層和視圖層頻繁通訊。
其實(shí)這類通信損耗問題,在業(yè)內(nèi)由來已久,react native和weex都有類似問題,weex提供了bindingx來解決。
但對于小程序來講,這類問題解決起來更容易。其實(shí)視圖層的webview,是有js環(huán)境的,只不過過去不給開發(fā)者開放。
如果在視圖層的js直接處理滾動或拖動交互、直接處理數(shù)據(jù)格式,就能避免大量通信損耗。
但對于小程序平臺而言,大量開放webview里的js編寫,違反了它的初衷,比如開發(fā)者會直接操作dom,影響性能體驗(yàn)。所以小程序平臺提出一種新規(guī)范,限制webview里可運(yùn)行的js的能力。這就是wxs、sjs、filter的由來。
從本質(zhì)來講,wxs、sjs、filter是一種被限制過的、運(yùn)行在視圖層webview里的js。它并不是真的發(fā)明了一種新語言。
WXS特征及適用場景
WXS具備如下特征:
- WXS是可以在視圖層(webview)中運(yùn)行的JS
- WXS無法修改業(yè)務(wù)數(shù)據(jù),僅能設(shè)置當(dāng)前組件的class和style
- WXS是被限制過的JavaScript,可以進(jìn)行一些簡單的邏輯運(yùn)算
- WXS可以監(jiān)聽touch事件,處理滾動、拖動交互
故可以得出WXS的適用場景,主要包括:
- 用戶交互頻繁、僅需改動組件樣式(比如布局位置),無需改動數(shù)據(jù)內(nèi)容的場景,比如側(cè)滑菜單、索引列表、滾動漸變等
- 純粹的邏輯計算,比如文本、日期格式化,通過WXS可以模擬實(shí)現(xiàn)Vue框架的過濾器,如下是一個通過wxs便捷實(shí)現(xiàn)首字母大寫的示例:
uni-app如何支持WXS
uni-app遵循Vue單文件組件(SFC)規(guī)范,組件/樣式/腳本是寫在一個.vue文件中的,但微信小程序是多文件分離(wxml/wxss/js/json)的,所以在微信端的主要工作是擴(kuò)展vue-template-compiler,解析template/style/script節(jié)點(diǎn),并正確生成到對應(yīng)的wxml/wxss/js文件中,具體編譯工作如下圖:
Tips-1:關(guān)于<wxs>標(biāo)簽重構(gòu)為<script lang="wxs">的說明:
因.vue文件中的<wxs>標(biāo)簽及內(nèi)嵌WXS代碼,在主流前端開發(fā)工具(vscode/HBuilderX等)中,均無法實(shí)現(xiàn)語法提示、代碼高亮及格式化,故uni-app將<wxs module="m1">重構(gòu)為<script module="m1" lang="wxs">,便捷實(shí)現(xiàn)了語法提示、代碼高亮等,如下為vscode/HBuilderX中對于<wxs>標(biāo)簽重構(gòu)前后的代碼高亮對比,明顯重構(gòu)為<script lang="wxs">后,開發(fā)體驗(yàn)更佳:
Tips-2:鑒于Vue的自定義標(biāo)簽規(guī)范,我們建議將<wxs>(<script lang="wxs">)和template平級編寫
編譯器的具體解析擴(kuò)展工作,這里不詳述,僅給出wxs生成的示例代碼,讓大家有個直觀理解:
createFilterTag (filterTag, {content,attrs}) {content = content.trim()if (content) { //<wxs>標(biāo)簽內(nèi)直接編寫 wxs 代碼return `<${filterTag} module="${attrs.module}">${content}</${filterTag}>`} else if (attrs.src) { //外聯(lián) .wxs 文件return `<${filterTag} src="${attrs.src}" module="${attrs.module}"></${filterTag}>`}}在保證編譯正確的情況下,微信小程序運(yùn)行時會正確解析并執(zhí)行WXS腳本,框架runtime無需干預(yù)。
基于 WXS 提升性能體驗(yàn)的實(shí)現(xiàn)示例
下面的gif圖是借助 WXS 實(shí)現(xiàn)的一個swipeaction示例,列表項(xiàng)向左滑動時拉出幾個擠壓式聯(lián)動的菜單按鈕,跟手動畫、回彈動畫都很自然流暢。
這里簡單給出主要實(shí)現(xiàn)思路:
該示例的完整源碼參考github
更多平臺的兼容性
uni-app的App端也是一個小程序引擎,所以想要在App端實(shí)現(xiàn)流暢的跟手拖動,也需要實(shí)現(xiàn)類似wxs的機(jī)制。
其實(shí)H5平臺倒不存在邏輯層和視圖層通訊折損的問題,但為了平臺兼容性拉齊,uni-app在H5端也實(shí)現(xiàn)了wxs機(jī)制。
這樣編寫wxs代碼,在uni-app中可同時運(yùn)行在App端、H5端、微信小程序端。
因百度小程序的Filter過濾器、支付寶小程序的SJS和微信小程序的WXS在語法上差異較大,uni-app只支持單獨(dú)編寫百度小程序的Filter過濾器和支付寶小程序的SJS,這兩種腳本無法跨多端,僅支持自有平臺。開發(fā)者若需使用,可分別編寫wxs/filter/sjs腳本,然后依次通過script引用,uni-app編譯器會根據(jù)目標(biāo)平臺,分別編譯發(fā)行,如下為示例代碼:
示例代碼要有條件編譯
后續(xù)
用運(yùn)行在視圖層的js解決通訊阻塞,可能很多人都沒意識到。希望本文能給大家解惑,解開WXS之謎。
其實(shí)小程序的性能體驗(yàn)優(yōu)化,仍然有大量空間。DCloud團(tuán)隊在這個領(lǐng)域研究了6年,清楚當(dāng)前的優(yōu)勢,也清楚當(dāng)前的問題。我們會繼續(xù)分享這些問題及對應(yīng)的解決方案,為小程序產(chǎn)業(yè)發(fā)展貢獻(xiàn)力量。
本文涉及的uni-ui的swiperaction組件,代碼開源在https://github.com/dcloudio/uni-ui,uni-app框架代碼開源在 https://github.com/dcloudio/uni-app,歡迎大家 star 或提交 pr。
總結(jié)
以上是生活随笔為你收集整理的谜之wxs,uni-app如何用它大幅提升性能的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: adb连接不上手机测试设备
- 下一篇: npmjs 注册上传代码流程