# 前言
渲染线程讲解完后。这一章节我们来探索一下微信小程序的通讯系统。来看一下渲染线程是如何通讯逻辑线程的。
本章节内容分解:
- 小程序通讯系统原理
# 通讯系统
先重顾看一下微信小程序的线程架构图。

可以看到sendData并不是直接指向逻辑层的(也就是Event这两条线)。小程序逻辑层和渲染层的通信会由 Native (微信客户端)做中转,逻辑层发送网络请求也经由 Native 转发。我们先留有这个概念。
# 通讯原理
Native做中转的话需要一个契机,就是WeixinJSBridge,WeixinJSBridge提供了渲染层与Native、Native与逻辑层之间消息通信的机制。机制是机制,那么具体的通讯手段是什么呢?
根据不一样的客户端通讯手段是不一样的,统一的机制为了更好的兼容不同的客户端,具体的通讯手段分为几种。
内置组件中有部分组件是利用到客户端原生提供的能力,既然需要客户端原生提供的能力,那就会涉及到渲染层与客户端的交互通信。这层通信机制在 iOS 和安卓系统的实现方式并不一样,iOS 是利用了 WKWebView 的提供 messageHandlers 特性,而在安卓则是往 WebView 的 window 对象注入一个原生方法,最终会封装成 WeiXinJSBridge 这样一个兼容层。在微信开发者工具中则是使用了websocket进行了封装。
在微信小程序执行过程中,Native层,也就是客户端层分别向渲染层与逻辑层注入WeixinJSBridge以达到线程通讯的目的,前面章节中在分析渲染层结构和逻辑层结构中我们也都看到了其中WeixinJSBridge的<script>标记注入,WeixinJSBridge提供了如下几个方法:
invoke- 调用Native API,以api方式调用开发工具提供的基础能力,并提供对应api执行后的回调。invokeCallbackHandler- Native 传递 invoke 方法回调结果on- 用来收集小程序开发者工具触发的事件回调publish- 渲染层发布消息,用来向逻辑业务层发送消息,也就是说要调用逻辑层的事件方法subscribe- 订阅逻辑层消息subscribeHandler- 视图层和逻辑层消息订阅转发setCustomPublishHandler- 自定义消息转发
上面说到初始化过程中Native层理论上是微信客户端,分别在视图层和业务逻辑层注入了WeixinJSBridge,但是由于运行环境的关系,比如我们现在正用的微信开发者工具来说,它并不是微信客户端,并没有Native。那么他是用什么手段进行线程与线程之间的通讯的呢?是Websocket。并且微信开发者工具在WeixinJSBridge的基础上进行了上面几个方法的重构,以达到调用微信开发者工具(IDE)功能目的。
那么是哪几个方法进行了重写呢,在源码中我们找到答案:

那我们就来继续探索一下,这几个方法。
首先这几个方法在微信开发者工具应用的文件夹中可以找到,目录为Contents/Resources/app.nw/js/extensions/pageframe/index.js。我们找到打开之后里面的代码依然是压缩的。这里使用js-beautify工具美化一下这个压缩的代码,以便于我们进行解析。
$ js-beautify index.js -o beautifyIndex.js
这样的话目录中就会多处一个美化后的js文件。建议把目标文件拷贝出来再进行操作。
打开这个“美化”之后的js文件后,发现依然还是很难读懂,哈哈,暂时我也没啥办法,有人认识小程序部门的人看看能不能要一份源码,记得发我一份。
在讲这几个方法之前我们先确认一个事情,就是微信开发者工具的通讯机制真的是websocket吗,我们从源码的角度来看一下。
# Websocket
首先我们找到上面所说的Websocket模块源码

可以看到模块内包含了websocket的创建、建立连接,收发数据,并且模块开放了一些方法,比如send、connect、registerCallback、removeCallback。
websocket建立连接了之后就是进行通讯协议约定,就像火车一样,你买的不一样的火车票,同样的火车就会拉你去不一样的地方。因为我们约定了不一样的火车票要去不一样的地方。
# invoke
invoke主要是用来 调用 Native API,在微信开发者工具中以api方式调用开发者工具提供的基础能力。
view层会统一向websocket服务发送command: WEBVIEW_INVOKE的命令,根据参数中的api值来确定调用开发者工具具体的api方法。调用完毕后,websocket服务向view层发送command: WEBVIEW_INVOKE_CALLBACK命令,渲染层根据此标识知道api调用完毕,然后执行对应的回调。
用过websocket的时候一样要约定一些通讯协议,比如PUBLISH_MAP_DATA: { k: v }。所上面的将的command就是这样约定的通讯协议来区分功能。
