作者:赵启明
链接:https://zhuanlan.zhihu.com/p/22754296
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

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

本文分为以下几个部分:

  • 小程序调试技巧

  • 小程序主要模块构成

  • 小程序模块间通信

  • 设计理念分析

小程序调试技巧

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

  • 找到 app.nw 项目根目录,Mac 下为/Applications/wechatwebdevtools.app/Contents/Resources/app.nw

  • 使用 js-beautify 对代码批量格式化:

    cd /Applications/wechatwebdevtools.app/Contents/Resources/app.nw
    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 方法发送:

    WeixinJSBridge.publish('PAGE_EVENT', data)

    data 参数举例:

    {"data": {"eventName": "onhidetap","data": {"target": {...},"currentTarget": {...},"type": "tap","timeStamp": 11457,"touches": [ ...  ],"detail": {...}}},"options": {"timestamp": 1475445858336}}
  3. 后台(开发者工具内为 nwjs 运行环境)将数据处理后发送给 service 模块,数据形如:

    {"to": "appservice","msg": {"eventName": "PAGE_EVENT","data": {"data": {"eventName": "onhidetap","data": {"target": {...},"currentTarget": {...},"type": "tap","timeStamp": 75329,"touches": [ ...  ],"detail": {...}}},"options": {"timestamp": 1475445858336}},"webviewID": 0},"command": "MSG_FROM_WEBVIEW"}
  4. service 模块的 WeixinJSBridge 内回调函数依据传来数据找到对应 view 的 page 模块后执行 对应名为 eventName 指向的函数

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

    {"appData": {"page/index": {...}},"sdkName": "send_app_data","to": "backgroundjs","comefrom": "webframe","command": "COMMAND_FROM_ASJS","appid": "touristappid","appname": "chat","apphash": 70475629,"webviewID": 100000}
    {"eventName": "appDataChange","data": {"data": {"data": {"hidden": true}},"options": {"timestamp": 1475528706311}},"sdkName": "publish","webviewIds": [0],"to": "backgroundjs","comefrom": "webframe","command": "COMMAND_FROM_ASJS","appid": "touristappid","appname": "chat","apphash": 70475629,"webviewID": 100000}
  6. 后台(文件 dist/components/simulator/webviewbody.js) 接收到appDataChange 事件数据后再将数据进行简单封装, 最后转发给到 view 层。 具体数据格式为:

    {"to": "webframe","msg": {"eventName": "appDataChange","data": {"data": {"data": {"hidden": true}},"options": {"timestamp": 1475528706311}},"sdkName": "publish","webviewIds": [0],"to": "backgroundjs","comefrom": "webframe","command": "COMMAND_FROM_ASJS","appid": "touristappid","appname": "chat","apphash": 70475629,"webviewID": 100000,"act": "sendMsgFromAppService"},"command": "MSG_FROM_APPSERVICE","webviewID": 0,"id": 0.10577065353216675}
  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 加以改造,我们便不难做到让 小程序跑在自己的环境下,这样就可以做些手机调试以及单页面测试等操作。

下一篇会为大家带来 view 模块和 service 模块内部结构分析,欢迎关注。

微信小程序架构分析 (上)相关推荐

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

    作者:赵启明 链接:https://zhuanlan.zhihu.com/p/22932309 来源:知乎 著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 这一篇拖了一段时间,原 ...

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

    2019独角兽企业重金招聘Python工程师标准>>> 本文探讨一下小程序的 view 模块和 service 模块是如何构成的. 你可以在app.nw/app/dist/weapp ...

  3. android 微信小程序原理,微信小程序架构原理

    前言 昨日看朋友圈,据说有人花钱买star,不知道真的假的?以前以为只是大家开玩笑.今日早读文章由百度EUX@田光宇投稿分享. 正文从这开始~~ 微信小程序 微信小程序包含下面四种文件: js jso ...

  4. ssm基于微信小程序的恋上诗词设计与实现毕业设计源码011431

    基于SMM微信小程序的恋上诗词设计与实现 摘  要 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,恋 ...

  5. java+SpringBoot+HTML+Mysq基于微信小程序的掌上博物馆游览

    详细功能设计:请点击下面链接查看 java+SpringBoot+HTML+Mysq基于微信小程序的掌上博物馆游览_哔哩哔哩_bilibili 源码+论文获取: 源码+论文获取请私信获取 摘  要 本 ...

  6. ssm+mysql+基于微信小程序的恋上诗词设计与实现 毕业设计-附源码011431

    基于SMM微信小程序的恋上诗词设计与实现 摘  要 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,恋 ...

  7. (附源码)ssm基于微信小程序的恋上诗词设计与实现 毕业设计 011431

    基于SMM微信小程序的恋上诗词设计与实现 摘  要 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,恋 ...

  8. php微信小程序多图上传,tp5实现微信小程序多图片上传到服务器功能

    最近在做一个教育类的小商城的微信小程序,用到了上传多个图片文件到服务器端,这里做一个讲解,希望对大家有所帮助. 1,小程序端: 在wxml文件中: 删除 点击上传作业 在js文件中: Page({ / ...

  9. uniapp 微信小程序开发 图片上传压缩

    uniapp 微信小程序开发 图片上传压缩 安卓上传图片并压缩 思路 全部代码 安卓上传图片并压缩 由于后端接口对图片的大小有限制,所以在上传图片是需要压缩处理: uni.chooseImage({c ...

最新文章

  1. Java多态-如何理解父类引用指向子类对象
  2. CDQ分治嵌套模板:多维偏序问题
  3. PyCairo 中的图片
  4. poj 3080 Blue Jeans kmp+枚举
  5. 漫画:如何将一个链表“逆序”?
  6. Java内存区域(运行时数据区)
  7. 二级c语言 办公软件高级应用,高级应用题库_计算机国二office高级应用考试的题目是从题库20套里抽其中一套还是别的题目_淘题吧...
  8. 清理window日志垃圾.bat
  9. 适合java初级程序员找工作的项目
  10. cherokee php,安装Cherokee与PHP5和MySQL支持在Mandriva 2009.1
  11. 编译优化之 - 常量传播入门
  12. 记录自己的鬼压床——长发
  13. vue spa项目转服务器渲染
  14. 老外的各种no-sql数据库的比较贴
  15. 数据中台稳定性的“四高” | StartDT Tech Lab 18
  16. 设计师必备!免费下载 PSD 素材的32个网站
  17. python 爬虫实践 (爬取链家成交房源信息和价格)
  18. 原始LBP/Uniform LBP编程实现与直方图
  19. WIN10 双显示器设置
  20. 一个序列的子序列个数

热门文章

  1. 各大网站屏蔽搜索引擎抓取分析
  2. android ExpandableListView
  3. 《Linux企业应用案例精解》一书已由清华大学出版社出版
  4. Exchange 分析器工具介绍及案例分析
  5. setleft android,android TextView的setCompoundDrawables()方法
  6. 我要回家软件_这个中秋节,我也要回家
  7. php 限制刷新,PHP禁止频繁刷新方法
  8. 磁共振检查头部能检测出什么_什么是磁共振血管造影?检查价格贵吗?
  9. influxdb java spring_Spring boot使用influxDB总结
  10. 三种云存储加密的方法