对webduino运行流程的分析
文章目录
背景
在前一篇关于blockly的文章中,我参考了webduino对Web Speech的包装,并将其移植到blockly4pi中。
webduino对blockly的使用,有许多出彩的地方。这篇文章将简要对其核心部分做个分析,为了更深入地借鉴它的设计
入手
我买了webduino的smart模块,所以我们从最简单的案例入手:将smart的led灯设为红色
首先当然是将smart连上wifi,完成后它分配到网址:192.168.0.119
(显示在wifi名称中)
接着我们拼搭出积木块
运行后,成功点亮红灯
分析
首先查看上边的积木生成的代码:
|
|
可以看到webduino通过积木生成js代码, 然后运行js代码来控制start.(我的blockly4pi同时生成js和python)
容易看出,boardReady是浏览器与start通信的代理,接着我们进入源码,去跟踪boardReaety
,它定义在这里
|
|
其中board定义在Board
通过EventEmitter传递全局消息
休眠一秒
在js中休眠是个有趣的话题,我们知道js是非阻塞的,webduino使用await来实现(很新的特性,之后会通过babel来在浏览器里编译,后文再说)
对应的代码是
|
|
这部分很有意思,我们仅仅添加一个等待一秒的模块,生成的代码结构整体变了,新添加的模块并不特殊,它生成的代码为
|
|
可以推测,代码在generate之前有个预处理,大概是根据generate出来的代码里是够包含await
关键字来处理,我们可以搜索源码来验证我们的想法:search await,果不其然
代码执行
早期
blockly-src/demos/code/code.js Code.runJS这个好理解,早期的做法,目前被废弃
早期的执行机制如注释中说的Just a quick and dirty eval
,简单粗暴
|
|
后来的机制颇为费解
后来的机制
我们可以从bindClick runButton追踪起、经过Code.reloadSandbox(),在这个函数中将模块generate为代码:Code.getContext,generate的过程会判断是否需要使用babel编译,如果需要会做好编辑,在之后的程序中用babel编译它:Code.transform
如此一来我们就得到了可在普通浏览器里运行的js代码,如果是早期的做法,至此丢到eval里就结束了,目前的做法要复杂些,把代码丢到一个iframe中跑,用到了iframe-api (本质上是window.postMessage)
一些核心步骤如下:
通信过程
websocket
我们先关注采用websocket的通信过程(本地运行)
onmessage handle定义了收到smart数据的回调
值得注意的是,数据的传输使用了二进制数据
之后通过事件系统发布消息,emit的定义之处在EventEmitter emit
ps:使用mqtt与云端通信的部分在这 MqttTransport.js
控制流
有了上边这些探索,我们可以挑战最后一个问题了,控制指令是如何抵达smart的,拿最初的例子来说,把点亮红灯积木块跑起来的时候发生了什么?
首先是积木生成对应的代码
|
|
board我们在前头说过,检索源码发现getRGBLedCathode不过是对webduino.module.RGBLed
的包装
于是我们到webduino-js继续探索.我们沿着rgbled.setColor('#ff0000');
一路追踪下去,看到DataTransfer.js , webduino采用二进制来通信,发送数据的地方定义在send -> sendOut 在此我们可以看到数据的发送也是用的二进制(收发都是)
其他感兴趣的地方
与页面元素交互
参考
文章作者 种瓜
上次更新 2017-05-21