您可以捐助,支持我们的公益事业。

1元 10元 50元





认证码:  验证码,看不清楚?请点击刷新验证码 必填



  求知 文章 文库 Lib 视频 iPerson 课程 认证 咨询 工具 讲座 Model Center   Code  
会员   
   
 
     
   
 订阅
  捐助
谜之wxs,uni-app如何用它大幅提升性能
 
作者:崔红保
 
  4118  次浏览      14
 2020-8-4
 
编辑推荐:
本文主要介绍微信为何要创造WXS,WXS特征及适用场景,uni-app如何支持WXS,并基于 WXS 提升性能体验的实现示例,希望对您的学习有所帮助。
本文来自于知乎,由火龙果软件Alice编辑推荐。

小程序技术领域,有几个谜一样的存在:微信的WXS、支付宝的SJS、百度的Filter。

很多开发者都不明白为什么要造这种语言脚本的轮子出来,甚至很多开发者根本不知道它们的存在。

其实几大小程序平台创造它们,都是为了解决性能问题,但不得不吐槽下,设计的实在是很难用,文档也语焉不详。

uni-app支持将WXS、SJS、Filter编译到这3家小程序平台,同时还在App和H5实现了WXS的解析。为什么做这些事?也是为了性能。

比如uni-ui组件库中的swiperaction组件,就是列表项向左滑动时拉出几个挤压式联动的菜单按钮,这种流畅的跟手动画,正是借助于WXS机制实现的。

微信为何要创造WXS

WXS(WeiXin Script)是微信创造的一套脚本语言,它的官方说法是:“WXS 与 JavaScript 是不同的语言,有自己的语法,并不和 JavaScript 一致”。

那微信为何要脱离 JavaScript ,单独创造一套语言呢?这要从微信小程序的底层逻辑(运行环境)讲起。

小程序的运行环境分为逻辑层和视图层,分别由2个线程管理,其中:

WXML 模板和 WXSS 样式工作在视图层,界面使用 WebView 进行渲染

JavaScript代码工作在逻辑层,运行在JsCore或v8里

小程序在视图层与逻辑层两个线程间提供了数据传输和事件系统。这样的分离设计,带来了显而易见的好处: - 逻辑和视图分离,即使业务逻辑计算非常繁忙,也不会阻塞渲染和用户在视图层上的交互

但同时也带来了明显的坏处: - 视图层(webview)中不能运行JS,而逻辑层JS又无法直接修改页面DOM,数据更新及事件系统只能靠线程间通讯,但跨线程通信的成本极高,特别是需要频繁通信的场景

什么是需要频繁通讯的场景?最典型的例子就是用户持续交互的情况,比如触摸、滚动等。我们以侧滑菜单为例,假设在页面上滑动A元素,要求B元素跟随移动,一次滑动操作(touchmove)的响应过程如下:

touchmove 事件从视图层(Webview)传递到逻辑层,中间会由微信客户端(Native)做中转

逻辑层处理 touchmove 事件,计算需移动的位置,然后再通过 setData 传递到视图层,中间同样会由微信客户端(Native)做中转

一次 touchmove 的响应需要经过 视图层、Native、逻辑层三者之间2个完整来回的通信,通信的耗时开销较大,用户的交互就会出现延时卡顿的情况。

除了滚动、拖动交互外,在for循环里对数据做格式修改,也会造成逻辑层和视图层频繁通讯。

其实这类通信损耗问题,在业内由来已久,react native和weex都有类似问题,weex提供了bindingx来解决。

但对于小程序来讲,这类问题解决起来更容易。因为其实视图层的webview,是有js环境的,只不过过去不给开发者开放。

如果在视图层的js直接处理滚动或拖动交互、直接处理数据格式,就能避免大量通信损耗。

但对于小程序平台而言,大量开放webview里的js编写,违反了它的初衷,比如开发者会直接操作dom,影响性能体验。所以小程序平台提出一种新规范,限制webview里可运行的js的能力。这就是wxs、sjs、filter的由来。

从本质来讲,wxs、sjs、filter是一种被限制过的、运行在视图层webview里的js。它并不是真的发明了一种新语言。

WXS特征及适用场景

WXS具备如下特征: - WXS是可以在视图层(webview)中运行的JS - WXS无法直接修改业务数据,仅能设置当前组件的class和style,或者对数据进行格式化。要修改逻辑层的数据,需要通过 callMethod,传递参数给逻辑层 - WXS是被限制过的JavaScript,可以进行一些简单的逻辑运算 - WXS可以监听touch事件,处理滚动、拖动交互

故可以得出WXS的适用场景,主要包括: - 用户交互频繁、仅需改动组件样式(比如布局位置),无需改动数据内容的场景,比如侧滑菜单、索引列表、滚动渐变等 - 数据格式处理,比如文本、日期格式化,或者国际化。通过WXS可以模拟实现Vue框架的过滤器,如下是一个通过wxs实现首字母大写的示例:

<wxs module="m1">
//首字母大写
var capitalize = function(value) {
if (!value) return ''
value = value.toString()
return value.charAt(0).toUpperCase() + value.slice(1)
}
module.exports = {
capitalize: capitalize
}
</wxs>
<view class="content">
<view class="text-area">
<!-- title 为当前页面 data 中定义的初始数据 -->
<text class="title">{{m1.capitalize(title)}}</text>
</view>
</view>

uni-app如何支持WXS

uni-app遵循Vue单文件组件(SFC)规范,组件/样式/脚本是写在一个.vue文件中的,但微信小程序是多文件分离(wxml/wxss/js/json)的,所以在微信端的主要工作是扩展vue-template-compiler,解析template/style/script节点,并正确生成到对应的wxml/wxss/js文件中,具体编译工作如下图:

Tips-1:关于<wxs>标签重构为<script lang="wxs">的说明:

因.vue文件中的<wxs>标签及内嵌WXS代码,在主流前端开发工具(vscode/HBuilderX等)中,均无法实现语法提示、代码高亮及格式化,故uni-app将<wxs module="m1">重构为<script module="m1" lang="wxs">,便捷实现了语法提示、代码高亮等,如下为vscode/HBuilderX中对于<wxs>标签重构前后的代码高亮对比,明显重构为<script lang="wxs">后,开发体验更佳:

Tips-2:鉴于Vue的自定义标签规范,我们建议将<wxs>(<script lang="wxs">)和template平级编写

编译器的具体解析扩展工作,这里不详述,仅给出wxs生成的示例代码,让大家有个直观理解:

createFilterTag (filterTag, {
content,
attrs
}) {
content = content.trim()
if (content) { //<wxs>标签内直接编写 wxs 代码
return `<${filterTag} module="${attrs.module}">
${content}
</${filterTag}>`
} else if (attrs.src) { //外联 .wxs 文件
return `<${filterTag} src="${attrs.src}" module="${attrs.module}"></${filterTag}>`
}
}

在保证编译正确的情况下,微信小程序运行时会正确解析并执行WXS脚本,框架runtime无需干预。

基于 WXS 提升性能体验的实现示例

下面的gif显示的内容,是借助 WXS 实现的一个swipeaction组件示例,列表项向左滑动时拉出几个挤压式联动的菜单按钮,跟手动画、回弹动画都很自然流畅。

这里简单给出主要实现思路:

在 vue 中引用 wxs 文件,并绑定 touch 事件

<template>
<view class="uni-swipe_content">
<!-- 可滑动的菜单项容器,绑定touch事件 -->
<view :data-position="pos" class="move-hock"
@touchstart="swipe.touchstart" @touchmove="swipe.touchmove" @touchend="swipe.touchend" @change="change">
<view class="uni-swipe_box">
<slot />
</view>
<view class="uni-swipe_button-group move-hock">
<!-- 滑动后,右侧挤压式的联动菜单按钮-->
<view v-for="(item,index) in options" :data-button="btn" :key="index" class="button-hock">
{{ item.text }}
</view>
</view>
</view>
</view>
</template>
<script module="swipe" lang="wxs" src="./index.wxs"></script>

在 wxs 文件中,处理 touch 事件逻辑,通过 translateX 移动元素位置

function touchstart(e, ins) {
//记录开始位置及动画状态
var pageX = e.touches[0].pageX;
....
}
function touchmove(e, ownerInstance) {
var instance = e.instance;
var pageX = e.touches[0].pageX;//获取当前移动位置
//计算偏移位置
var x = Math.max(-instance.getState().position[1].width, Math.min((value), 0));
//设置左侧元素移动位置
instance.setStyle({transform: 'translateX(' + x + 'px)'})
//循环右侧挤压式联动菜单
var btnIns = ownerInstance.selectAllComponents('.button-hock');
for (var i = 0; i < btnIns.length; i++) {
...
//设置每个联动菜单的移动位置
btnIns[i].setStyle({transform: 'translateX(' + (arr[i - 1] + value * (arr[i - 1] / position[1].width)) + 'px)'})
...
}
}
function touchend(e, ownerInstance) {
var instance = e.instance;
var state = instance.getState()
//根据当前移动位置,实现菜单项的自动展开或回弹
move(state.left, -40, instance, ownerInstance)
}

该示例的完整源码参考github

在这段代码中,响应手势并移动菜单,是在视图层直接完成的。而不用wxs的传统写法,实现这个功能就会很卡。首先是视图层接收到touch事件,然后传递给逻辑层,逻辑层的js响应touch事件,判断移动距离,再通知视图层更新界面元素的位置。在持续的拖动过程中,视图层和逻辑层不停交互通信,无法做到跟手的顺滑。

虽然我们了解了wxs的原理,但老实讲,wxs挺难用的,直到现在,大多数开发者仍然不会用它。比较合适的做法,还是一些框架的作者对它进行封装。uni-app提供的uni-ui组件库,就是这样做的,开发者只需要按标准vue组件的方式去引用uni ui的swiperaction组件,就能得到流畅的滑动跟手菜单。

更多平台的兼容性

uni-app的App端也是一个小程序引擎,为了在App端实现流畅的跟手拖动,也实现和兼容了wxs。

其实H5平台倒不存在逻辑层和视图层通讯折损的问题,但为了平台兼容性拉齐,uni-app在H5端也实现了wxs机制。

这样编写wxs代码,在uni-app中可同时运行在App端、H5端、微信小程序端。

百度小程序的Filter过滤器和支付宝小程序的SJS,成熟度还比较低,目前只能处理基本的数据格式过滤,还不能响应touch等交互事件。

至于头条和QQ小程序,还不支持类WXS机制。

期待其他小程序平台尽快补齐这个重要功能,实现体验的提升。

uni-app目前也支持单独编写百度小程序的Filter过滤器和支付宝小程序的SJS,这两种脚本无法跨多端,仅支持自有平台。开发者若需使用,可分别编写wxs/filter/sjs脚本,然后依次通过script引用,uni-app编译器会根据目标平台,分别编译发行,如下为示例代码: 示例代码要有条件编译

<!-- App/H5/微信小程序平台调用wxs脚本 -->
<script module="utils" lang="wxs" src="./utils.wxs"></script>
<!-- 百度小程序平台调用filter.js脚本 -->
<script module="utils" lang="filter" src="./utils.filter.js"></script>
<!-- 支付宝小程序平台调用sjs脚本 -->
<script module="utils" lang="sjs" src="./utils.sjs"></script>

后续

用运行在视图层的js解决通讯阻塞,可能很多人都没意识到。希望本文能给大家解惑,解开WXS之谜。

其实小程序的性能体验优化,仍然有大量空间

 
   
4118 次浏览       14
相关文章

深度解析:清理烂代码
如何编写出拥抱变化的代码
重构-使代码更简洁优美
团队项目开发"编码规范"系列文章
相关文档

重构-改善既有代码的设计
软件重构v2
代码整洁之道
高质量编程规范
相关课程

基于HTML5客户端、Web端的应用开发
HTML 5+CSS 开发
嵌入式C高质量编程
C++高级编程
最新课程计划
信息架构建模(基于UML+EA)3-21[北京]
软件架构设计师 3-21[北京]
图数据库与知识图谱 3-25[北京]
业务架构设计 4-11[北京]
SysML和EA系统设计与建模 4-22[北京]
DoDAF规范、模型与实例 5-23[北京]
 
最新文章
如何设计高扩展的在线网页制作平台
electron入门心得
使用 Electron 构建桌面应用
VUE.JS组件化开发实践
深入理解JSCore
最新课程
HTML 5 + CSS3 原理与开发应用
Web前端高级工程师必备技能实战
Vue大型项目开发实战
React原理与实践
Vue.js进阶与案例实践
更多...   
成功案例
中交集团 构建Web自动化测试框架
某著名电信公司 Vue.js进阶与案例
国电通网络技术 HTML5+CSS3 +web前端框
移动通信 移动互联网应用开发原理
某电力行 android开发平台最佳
更多...