微信小程序架构分析 (上)

【引自第九程序的博客】相信不少上手试用了微信小程序开发者工具的开发者都会对其实现有些疑惑, 本文试图对其架构模型进行一些解析。如有错误之处,欢迎留言指出。

本文分为以下几个部分:

  • 小程序调试技巧
  • 小程序主要模块构成
  • 小程序模块间通信
  • 设计理念分析

小程序调试技巧

微信开发者工具默认禁用了右键打开调试面板功能,我们可以修改开发者工具部分代码移除该限制。

  • 找到 app.nw 项目根目录,Mac 下为/Applications/wechatwebdevtools.app/Contents/Resources/app.nw
  • 使用 js-beautify 对代码批量格式化:

  1. cd /Applications/wechatwebdevtools.app/Contents/Resources/app.nw 
  2. find . -type f -name '*.js' -not -path "./node_modules/*" -not -path "./modified_modules/*" -exec js-beautify -r -s 2 -p -f '{}' \;  
  • 注释掉文件 app/dist/app.js 44
    行和app/dist/components/simulator/webviewbody.js 149 行preventDefault
    调用。101100 版本还需要修改 package.json 文件,去掉 --disable-devtools。

执行完以上操作就可以右键打开页面的调试面板了,需要特别注意的是,使用 view 页面的面板后会导致 wxml 面板不可用,touch 事件无法响应等种种问题,请慎重使用。

通过代码可以发现,在配置目录下添加 config.json 文件,然后加入{isDev:true} 可以启用开发者工具所谓的调试模式, 但是我在配置后程序无法正常启动,只好暂时先放弃这种方式。

小程序主要模块构成

小程序自身分为两个主要部分独立运行:view 模块和 service 模块。在开发者工具中,它们独立运行于不同的 webivew tag 中。

view 模块负责 UI 显示,它由开发者编写的 wxml 和 wxss 转换后代码以及微信提供相关辅助模块组成。 一个 view
模块对应一个 webview 组件(也就是我们常规理解的一个页面), 小程序支持同时多个 view 存在。view 模块通过
WeixinJSBridge 对象来跟后台通信。

service 模块负责应用的后台逻辑,它由小程序的 js 代码以及微信提供的相关辅助模块组成。 一个应用只有一个 service
进程,它同样也是一个页面(至少在开发者工具内如此,上线后可能运行于 WeixinJSCore 之内),与 view
模块不同的是,它在程序生命周期内后台运行,service 模块通过与 view 模块实现不同但接口格式一样的 WeixinJSBridge
对象跟后台通信。

小程序模块间通信

(开发者工具内各模块通信图)

做过微信开发相关的开发者会对 WeixinJSBridge 这个对象有所了解,它就是负责 UI 与后台 进行交互的一个中间层。应用号的
WeixinJSBridge 相比与之前的微信 webview 多出 publish 和 subscribe
两个公共方法来发布和订阅事件,从而进行双向通信。

service 模块的 WeixinJSBridge 对象在文件app/dist/weapp/appservice/asdebug.js
中定义, view 层的 WeixinJSBridge 在文件 app/dist/inject/jweixindebug.js 中定义。
尽管两者都使用一样的接口以及使用 postMessage 方法与后台通信,但是其内部所做的事情确是完全不同的, 例如 service
模块可以直接通过 prompt 方法来通过 prompt调起底层组件,而 view 层的 WeixinJSBridge 只能发送消息 (参考
H5与Native交互之JSBridge技术)。

我们来看一个典型的交互流程:

1.用户点击界面触发事件

2.对应 view 模块接收事件后将事件封装成所需格式后调用 publish 方法发送:


  1. WeixinJSBridge.publish('PAGE_EVENT', data) 

data 参数举例:


  1. "data": { 
  2.   "eventName": "onhidetap", 
  3.   "data": { 
  4.     "target": { 
  5.       ... 
  6.     }, 
  7.     "currentTarget": { 
  8.       ... 
  9.     }, 
  10.     "type": "tap", 
  11.     "timeStamp": 11457, 
  12.     "touches": [ ...  ], 
  13.     "detail": { 
  14.       ... 
  15.     } 
  16.   } 
  17. }, 
  18. "options": { 
  19.   "timestamp": 1475445858336 
  20. }  

3.后台(开发者工具内为 nwjs 运行环境)将数据处理后发送给 service 模块,数据形如:


  1. "to": "appservice", 
  2. "msg": { 
  3.   "eventName": "PAGE_EVENT", 
  4.   "data": { 
  5.     "data": { 
  6.       "eventName": "onhidetap", 
  7.       "data": { 
  8.         "target": { 
  9.           ... 
  10.         }, 
  11.         "currentTarget": { 
  12.           ... 
  13.         }, 
  14.         "type": "tap", 
  15.         "timeStamp": 75329, 
  16.         "touches": [ ...  ], 
  17.         "detail": { 
  18.           ... 
  19.         } 
  20.       } 
  21.     }, 
  22.     "options": { 
  23.       "timestamp": 1475445858336 
  24.     } 
  25.   }, 
  26.   "webviewID": 0 
  27. }, 
  28. "command": "MSG_FROM_WEBVIEW" 
  29. }  

4.service 模块的 WeixinJSBridge 内回调函数依据传来数据找到对应 view 的 page 模块后执行 对应名为 eventName 指向的函数

5.回调函数调用 this.setData({hidden: true}) 改变 data,serivce 层计算该页面 data 后向后台发送 send_app_data 和 appdataChange 事件,具体数据格式如下:


  1. "appData": { 
  2.   "page/index": { 
  3.     ... 
  4.   } 
  5. }, 
  6. "sdkName": "send_app_data", 
  7. "to": "backgroundjs", 
  8. "comefrom": "webframe", 
  9. "command": "COMMAND_FROM_ASJS", 
  10. "appid": "touristappid", 
  11. "appname": "chat", 
  12. "apphash": 70475629, 
  13. "webviewID": 100000 
  14. }  

  1. "eventName": "appDataChange", 
  2. "data": { 
  3.   "data": { 
  4.     "data": { 
  5.       "hidden": true 
  6.     } 
  7.   }, 
  8.   "options": { 
  9.     "timestamp": 1475528706311 
  10.   } 
  11. }, 
  12. "sdkName": "publish", 
  13. "webviewIds": [ 
  14.   0 
  15. ], 
  16. "to": "backgroundjs", 
  17. "comefrom": "webframe", 
  18. "command": "COMMAND_FROM_ASJS", 
  19. "appid": "touristappid", 
  20. "appname": "chat", 
  21. "apphash": 70475629, 
  22. "webviewID": 100000 
  23. }  

6.后台(文件 dist/components/simulator/webviewbody.js) 接收到appDataChange 事件数据后再将数据进行简单封装, 最后转发给到 view 层。 具体数据格式为:


  1. "to": "webframe", 
  2. "msg": { 
  3.   "eventName": "appDataChange", 
  4.   "data": { 
  5.     "data": { 
  6.       "data": { 
  7.         "hidden": true 
  8.       } 
  9.     }, 
  10.     "options": { 
  11.       "timestamp": 1475528706311 
  12.     } 
  13.   }, 
  14.   "sdkName": "publish", 
  15.   "webviewIds": [ 
  16.     0 
  17.   ], 
  18.   "to": "backgroundjs", 
  19.   "comefrom": "webframe", 
  20.   "command": "COMMAND_FROM_ASJS", 
  21.   "appid": "touristappid", 
  22.   "appname": "chat", 
  23.   "apphash": 70475629, 
  24.   "webviewID": 100000, 
  25.   "act": "sendMsgFromAppService" 
  26. }, 
  27. "command": "MSG_FROM_APPSERVICE", 
  28. "webviewID": 0, 
  29. "id": 0.10577065353216675 
  30. }  

7.view 层的 WeixinJSBridge 接收到后台的数据,如果 webviewID 匹配则将 data 与现有页面 data 合并, 然后就是 virtual dom 模块进行 diff 和 apply 操作改变 dom。

小程序模块间消息传递除了界面事件和应用数据还包括触发原生方法、握手以及生命周期等类型, 尽管处理对象和处理方式不同,大体流程跟上面是一样的。

view 模块和 service 模块的 WeixinJSBridge 都使用了 postMessage 接口 (参考MDN 文档)
与后台通信,但是由于该接口无法直接与 nwjs 后台进程通信,所以开发者工具会将
app/dist/contentscript/contentScript.js 文件做为contentScript 注入到 view 模块和
service 模块所在页面,contentScript.js 的代码提供了 message 消息到
chrome.runtime通信接口的转换。

微信开发者工具扩展了 devtools 提供了 AppData 面板,开发者可以修改里面数据然后直接看到 view
界面的变化效果。这里修改数据后 nwjs 会将消息发送给 service 层,之后发生的事就跟上面 4 5 6 步一样:service
传递消息给 nwjs,最后到 view 层。

设计理念分析

小程序这样的分层设计显然是有意为之的,它的中间层完全控制了程序对于界面进行的操作, 同时对于传递的数据和响应时间也做到的监控。一方面程序的行为受到了极大限制, 另一方面微信可以确保他们对于小程序内容和体验有绝对的控制。

我们在小程序的 js 代码里面是不能直接使用浏览器提供的 DOM 和 BOM 接口的,这一方面是因为 js
代码外层使用了局部变量进行屏蔽,另一方面即便我们可以操作 DOM 和 BOM 接口,它们对应的 也是 service
模块页面,并不会对页面产生影响。

这样的结构也说明了小程序的动画和绘图 API 被设计成生成一个最终对象而不是一步一步执行的样子, 原因就是 json 格式的数据传递和解析相比与原生 API 都是损耗不菲的,如果频繁调用很可能损耗 过多性能,进而影响用户体验。

理解了以上机制,再对 view 模块和 service 模块的 WeixinJSBridge 加以改造,我们便不难做到让 小程序跑在自己的环境下,这样就可以做些手机调试以及单页面测试等操作。

作者:第九程序

来源:51CTO

时间: 2024-11-01 05:33:24

微信小程序架构分析 (上)的相关文章

微信小程序架构分析 (下)

[引自第九程序的博客]这一篇拖了一段时间,原因是实现一个可以运行微信小程序的 web 环境比我想象中要困难一些, 这一方面是因为微信对于代码进行了压缩混淆,另一方面主要原因是开发者工具内部逻辑调用比较复杂(难怪 bug 不少),完全无法拿出来重用. 小程序实时运行工具 wept 的开发已经基本完成了, 你可以通过我的代码对小程序的 web 环境实现有更全面的认识.下面我将介绍它的实现过程以及实时更新的原理. 小程序 web 服务实现 我在 wept 的开发中使用 koa 提供 web 服务,以及

微信小程序架构分析 (中)

[引自第九程序的博客]本文探讨一下小程序的 view 模块和 service 模块是如何构成的. 打开微信 web 开发者工具,然后输入 openVendor() 便会打开 WeappVendor这个目录,这里包含了 view 模块和 service 模块使用的几个核心文件: wcc 可执行程序,用于将 wxml 转为 view 模块使用的 js 代码,使用方式为wcc xxx.wxml wcsc 可执行程序,用于将 wxss 转为 view 模块使用的 css 代码,使用方式为 wcsc xx

微信小程序人为的线上导流限制转为线下连接

微信小程序无法分享到朋友圈,甚至无法通过长按二维码进入,也就是说,即使你在一个网页或一篇订阅号的文章里放上小程序的二维码,用户还是无法长按打开小程序.用户只能通过:线下扫码. 搜索.朋友分享来打开小程序.微信人为地限制了小程序的线上导流,通过主动搜索进入,量显然不会特别大,朋友之间的分享,扩散的速度也有限,可以说,微信在逼迫开发者尝试线下的导流渠道.这与微信想通过二维码连接现实世界的战略是具有一致性的. 为什么是线下?如果前面的论述是正确的,那么,小程序的出现,要解决的就不是 HTML5 的体验

移动开发之微信小程序——资料集合

本文转载自:知乎 有需要下载的客官可可以点击知乎去下载相关资料 一:官方地址集合:1:官方工具:https://mp.weixin.qq.com/debug/wxadoc/dev/devtools/download.html?t=14764346784612:简易教程:https://mp.weixin.qq.com/debug/wxadoc/dev/?t=14764346775993:设计指南:https://mp.weixin.qq.com/debug/wxadoc/design/index

史诗手册!微信小程序新手自学入门宝典!你想要的都在这里

一.小程序官方指南 1:官方开发工具下载: https://mp.weixin.qq.com/debug/wxadoc/dev/devtools/download.html?t=201714 0.12.1304Win版:https://pan.baidu.com/s/1miNleBY 0.12.1304Mac版:https://pan.baidu.com/s/1qYNIQZy 2:官方提供的简单教程 https://mp.weixin.qq.com/debug/wxadoc/dev/ 3:小程序

微信小程序 require机制详解及实例代码_JavaScript

微信小程序 require机制详解 一, JS模块加载:一次性加载全部JS, 但并不一定立即执行. 先提一提微信小程序架构: 类浏览器 -> HTTP本地服务 -> 云端服务 微信小程序运行的架构,基本上是浏览器 -> HTTP本地服务 -> 云端服务, HTTP本地服务用来读取本地文件或者代理云端的文件资源.读取项目中JS文件, 是由HTTP本地服务取本地存储的脚本文件. 似乎比较简单,一个HTML 引用所有JS文件 既然采用了这种架构,那微信小程序就类似浏览器那样,借助一个HT

微信小程序学习之初探小程序_相关技巧

前言 9月21日,传言已久的微信应用号正式以"微信公众平台小程序"的名义发布,依然采取了内测制度,目前只有少部分开发者可使用."微信之父"张小龙在朋友圈介绍,这种小程序是一种不需要下载安装即可使用的应用,用户扫一扫或者搜一下即可打开应用,对用户来说应用触手可及,对微信来说体现了用完即走的理念.应用号出来之后,有人说微信这次要颠覆AppStore了,开发者直接基于微信开发小程序就可以了,不用开发什么App了.更有人说微信就是一个操作系统,真的如此吗?不管怎样,我们下面

微信小程序生态的3个阶段

微信小程序生态的 3 个阶段.小程序想要什么这篇文章其实是比较发散的,如果你已经读到这里,那么,让我们回到小程序本身吧.因为写了不少关于小程序的文章,过去几个月很多人问我小程序适合做什么,应该怎样做,我的理解是这样的: 小程序是一个生态 这个生态希望连接更多线下场景 生态里出现的产品,会分 3 个阶段 这 3 阶段分别为:   摸索与搬迁阶段 第一个阶段,以开发者的摸索和互联网公司的搬迁为主.开发者会在这个平台做各种小玩意尝鲜,看看能玩出什么花.互联网公司会把已有的业务,复制一份到小程序平台,比

微信小程序想要连接一切

马化腾在「世界互联网大会」上提出腾讯要「连接一切」,要成为互联网连接器.毫无疑问,连接一切的重任落在了微信身上.何为连接一切?连接人与人.连接人与服务.连接人与商业.连接人与物品,物品仍然没被连接,怎么办?微信小程序或许可以解决这个问题. 人与人之间的连接,第一个版本的微信已经实现,目前,微信已经有超过 8 亿的日活用户,几乎每个有手机的中国人,已经被微信连接. 人与服务的连接,也基本上通过服务号和微信内置的服务连接起来.这里所说的服务包括了内容.我们可以在微信里完成阅读.购物.娱乐等. 人与商