

微信小程序架构原理
source link: http://eux.baidu.com/blog/fe/%E5%BE%AE%E4%BF%A1%E5%B0%8F%E7%A8%8B%E5%BA%8F%E6%9E%B6%E6%9E%84%E5%8E%9F%E7%90%86
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

微信小程序架构原理
微信小程序
微信小程序包含下面四种文件:
- json 配置文件
- wxml 小程序专用 xml 文件
- wxss 小程序专用 css 文件
<view>
<text class="window">{{ text }}</text>
</view>
Page({
data:{
text:"这是一个页面"
},
onLoad:function(options){
// 页面初始化 options为页面跳转所带来的参数
},
// ........
})
微信小程序只能通过其 mvvm 的模板语法来动态改变页面,本身 js 并不支持 BOM 和 DOM 操作。
从开发工具看微信小程序架构
在 mac 端直接解压应用 发现 app.nw 文件夹,即开发工具源码。可以知道该项目由 nw.js 编写; 在 package.json 文件下找到应用入口:app/html/index.html
。入口 js 为 dist/app.js
我们可以看到整个编辑器的大致逻辑。
但我们关心的是构建过程,在 weapp 文件夹下存在 build.js 文件。没有找到有用的信息,只看到了 upload
模块,包括对大小限制,上传包命名。
为此怀疑,微信小程序本身和 RN 类似。是在服务端打包成 native 语言的。但是通过 android 边框测试发现,微信小程序根本不是 native 原生内容。
原生界面效果:

继续在 trans 文件夹下发现了编译模板。
- transWxmlToJs wxml 转 js
- transWxssToCss wxss 转 css
- transConfigToPf 模板页配置
- transWxmlToHtml wxml 转 html
- transManager 管理器
用到的内容:
- 发现用到了一个模板:
app.nw/app/dist/weapp/tpl/pageFrameTpl.js
,app.mw/app.dist.weapp/tpl/appserviceTpl.js
- wcc 可执行程序,wcc 用于转转 wxml 中的自定义 tag 为 virtual_dom
- wcsc 可执行程序,用于将 wxss 转为 view 模块使用的 css 代码,使用方式为
wcsc xxx.wxss
在模板中,我们发现使用了 WAWebview.js
文件,WAService.js
文件。 在 transWxmlToJs 中我们发现一段 generateFuncReady 事件的函数。对比注册该事件的函数在 WAWebview.js
中。
我们尝试使用 wcc 对input.xml 文件进行编译。
wcc -d input.xml
生成了一段脚本:
window.__wcc_version__ = 'v0.6vv_20161230_fbi'
var $gwxc
var $gaic =
$gwx = function (path, global) {
function _(a, b) {
b && a.children.push(b);
}
....
通过代码我们发现,调用 $gwx 函数会再生成一个有返回值的函数(前提是 path 填写正确);于是我们执行如下代码:
$gwx("input.xml")("test")
得出如下内容:
{
"tag": "wx-page",
"children": [
{
"tag": "wx-view",
"attr": {
"class": "section"
},
"children": [
{
"tag": "wx-input",
"attr": {
"autoFocus": true,
"placeholder": "这是一个可以自动聚焦的input"
},
"children": []
}
]
}
]
}
这应该是一个类似 Virtual dom 的对象,交给了 WAWebivew.js 来渲染,标签名为 wx-view
, wx-input
。
WAWebview.js
代码在最一开始提供的是兼容性工具,还有一个
WeixinJSBridge
引入。接下来是一个
Reporter
对象,它的作用就是发送错误和性能统计数据给后台。

wx
核心对象,包含了wx
对象下的api
。但是这里的api
数量远远少于官方的api
文档数量。

我们可以在代码里面发现,wx
下注册的 api
最终都会调用 WeixinJSBridge
方法。这个方法应该是在打包的时候端上注入的。我们也可以在 WAServeice.js
中找到该方法的定义。

所以我们得到了一个结论,WAService.js
是编辑器用来接受 wx
方法回调的代码。
wxparser
对象,提供dom
到wx element
对象之间的映射操作,提供元素操作管理和事件管理功能。之后代码是对
exparser
对象的处理,包括注册WeixinJSBridge
全局事件,Virtual dom 算法实现,样式注入等。介绍几个组件重要的内容
exparser.registerBehavior
注册组件基础行为,供组件继承。exparser.registerElement
为各种内置组件,注册模板,行为,属性,监听器等内容
这里我们观察到,组件:wx-video
, wx-canvas
, wx-contact-button
, wx-map
, wx-textarea
等 behaviors 都含有 "wx-native" 属性。这是不是意味着,这类组件都是 native 原生实现的呢。我们打开边框检查,发现这类组件确实都是原生的组件。

综上,微信小程序的界面有部分组件使用原生方式实现的,native 组件层在 WebView 层之上。大部分还是用前端实现的,这样解释了微信小程序的一个bug。
微信官方文档:
因为 scroll-view 是前端实现,在里面使用 native 组件,这样就无法监听滚动了。
WeixinJSBridge
组件是需要数据来渲染的,查看文档我们知道发送请求的 api 为 wx.request
;通过上面分析,我们知道 wx.request 实际调用的是 WeixinJSBridge
。现在我们看看 WeixinJSBridge

WeixinJSBridge
真正发送处理数据请求的是这段代码;如果当前环境是 ios
, 那么调用 WKWebview
的 window.webkit.messageHandlers.invokeHandler.postMessage
。如果所处环境是 android
则调用 WeixinJSCore.invokeHandler
(调用的时候,默认会带上当前 webviewID
)。
WAService.js
在对 WeixinJSBridge.js
分析中,我们并没有发现前端的通讯功能,路由能力,数据绑定等内容。进一步查看找到了一个 WAService.js
文件。 查看 WAService.js
文件源码:
- 在代码最开始,跟
WAWebview.js
一样的WeixinJSBridge
兼容模块 - 然后是跟
WAWebview.js
一样的Reporter
模块。 - 比
WAWebview.js
中wx
功能更为丰富wx
接口模块。(剩余部分wx api
都在这里) appServiceEngine
模块,提供Page
,App
,GetApp
接口- 为
window
对象添加AMD
接口require define
综上,WAService.js
主要实现的功能:
- App( ) 小程序的入口;Page( ) 页面的入口
- wx API;
- 页面有的作用域,提供模块化能力
- 数据绑定、事件分发、生命周期管理、路由管理
到这里我们得出结论,小程序的架构方案:

整个小程序由两个 webview
组成,代码分为 UI
层和逻辑层。UI
层运行在第一个 WebView
当中,执行 DOM
操作和交互事件的响应,里面是 WAWebview.js
代码及编译后的内容。逻辑层执行在(第二个webview
中)独立的 JS
引擎中(iOS:JavaScriptCore
, android:X5
JS解析器;统称 JSCore
;开发工具中,nwjs Chrome 内核),WAService.js 代码和业务逻辑。
当我们对 view
层进行事件操作后,会通过 WeixinJSBridge
将数据传递到 Native
系统层。Native
系统层决定是否要用 native
处理,然后丢给 逻辑层进行用户的逻辑代码处理。逻辑层处理完毕后会将数据通过 WeixinJSBridge
返给 View
层。View
渲染更新视图。
架构的讨论
微信的这种架构,对逻辑和UI进行了完全隔离,小程序逻辑和UI完全运行在2个独立的Webview里面来处理。那么这么做的好处是啥?总感觉更加麻烦了。除了小程序外,还有人采用这种架构设计么?
在网上搜索了一下,目前使用这种架构的项目还真有一个:去哪儿最新的 YIS 框架
YIS 采取了类似小程序的架构,分为逻辑层和UI层。UI 层运行在 WebView 中,而逻辑层运行在独立的 JS 引擎中。相应地,整个应用的代码,也分为两个大的部分,一部分运行在 WebView 中,一部分运行在JS引擎中。JS引擎计算DOM结构输出给WebView,WebView转发用户的点击事件给JS引擎。
该项目做法和小程序十分类似,唯一缺少的就是没有 native 的组件吧。然而官方文档上也没有任何介绍,为什么要这么做,只是说更流畅了。
传统 web 页面显示需要经历一下几个步骤:
webview
初始化- 加载
HTML
,CSS
,JS
- 编译
JS
Render
计算DOM Path
而利用小程序架构后,我们就可以将上述过程拆解成两部分并行执行: webview
部分:
webview
初始化- 加载
HTML
,CSS
,JS
(经过拆分后,体积大幅度减小) - 编译
JS
- 等待页面需要的数据
- 反序列化数据
- 执行
Patch
- 等待更多消息
jscore
部分:
- 加载框架
js
代码 - 编译
js
- 加载业务逻辑
js
代码 - 编译
js
- 计算首屏虚拟
DOM
结构 - 序列化数据,传输
- 等待
webview
消息,或者Native
消息
这样渲染进程和逻辑进程分离,并行处理:加速首屏渲染速度;避免单线程模型下,js
运算时间过长,UI 出现卡顿。 完全采用数据驱动的方式,不能直接操作 DOM,利用定制开发规范的方式避免低质量的代码的出现。
当然这种架构方案也有一定的缺点:
- 不能灵活操作
DOM
,无法实现较为复杂的效果 - 部分和
NA
相关的视图有使用限制,如微信的scrollView
内不能有textarea
。 - 页面大小、打开页面数量都受到限制
- 需要单独开发适配,不能复用现有代码资源。
- 在 jscore 中JS 体积比较大的情况下,其初始化时间会产生影响。
- 传输数据中,序列化和反序列化耗时需要考虑
Recommend
-
152
HashMap是常考点,而一般不问List的几个实现类(偏简单)。以下基于JDK1.8.0_102分析。 JDK版本:oracle java 1.8.0_102 HashMap的内部存储是一个数组(bucket),数组的元素Node实现了是Map.Entry接口(hash, key, value, n...
-
68
-
18
转载自微信开放社区: https://developers.weixin.qq.com/community/develop/article/doc/0006a6326b8d38e56b998833456813
-
8
微信小程序架构分析 (下)赵启明开源开发者,vimer这一篇拖了一段时间,原因是实现一...
-
20
微信小程序架构分析 (中)赵启明开源开发者,vimer本文探讨一下小程序的 view 模块和...
-
7
微信小程序架构分析 (上)赵启明开源开发者,vimer相信不少上手试用了微信小程序开发...
-
9
鸿蒙 “JS 小程序” 数据绑定原理详解 拜拜了,2020!来看看这一年你在社区做了什么~ 你的 2021 又会有哪些关键词? ...
-
6
微信小程序基础架构浅析已认证的官方帐号作者:lisaling,腾讯 IEG 游戏运营工程师。 微信小程序,简称小程序,英文 mini program。是一种不需要下...
-
5
您现在的位置:首页 --> 系统架构 --> 微信二维码登录的原理 微信二维...
-
3
双线程架构 在这之前,我们先来思考一个问题,小程序在架构上为什么会选择双线程? 为什么是双线程? 加载及渲染性能 小程序的设计之初就是要求快速,这里的快指的是加...
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK