添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
ReactNative 知识小集(1)-深入理解 React Native Debugging

ReactNative 知识小集(1)-深入理解 React Native Debugging

翻译改编自 Shaheen Ghiassy的 Deep Diving React Native Debugging from medium.com


中文译名 : 深入理解 React Native Debugging


译者注: 使用React Native(以下简称RN) Debug更是每天都会用到的技能.最近闲来看看一些原理性的文章,决定先从debug入手,可以更深入了解到框架背后的东西.原作者写这篇文章的时候RN还是0.11版本,我的开发版本是 0.47.其实debug的原理没有改变,只是个别环节的实现function增加了一些参数.下面我们开始正文


如果你和我一样,当你看到React Native 简单的debugging的时候,你一定会觉得这太拽了.在Chrome浏览器里打下断点,就可以终端iOS应用.而且可以console和watch各种变量.


但如果你和我一样,你一定不会相信编程中有魔法的存在,而要去探究他的工程实现.这篇文章就是带你理解React Native Debugging 背后的原理.


tl;dr 文章很长,不喜勿读


三方清单


  1. 一个NodeJS server. 称为 Packager. 运行在 terminal中
  2. Chrome 浏览器从Packager加载你的React Native JavaScript,并提供内置的debugging 支持,就像 debug 普通的JavaScript代码一样
  3. 设备上跑的App 和 在浏览器中跑的js应用 通过webSocket 通信. 设备和浏览器互相通过JSON命令通讯,浏览器来控制设备. 当然站在浏览器背后的是这个 Packager.


下面就来详细讲述这三方的关系.


深入理解


如果你想继续了解,你会对和debugging有关的过程,文件和操作更感兴趣.


Note: React Native 发展迅速, 本篇文章基于 React Native 0.47 版本


让我们先来直观的感受一下上面提到的三方+你的代码


* 一个典型的react应用中的各个角色


这四方之前的关系图有点小复杂,我们会慢慢展开.Facebook和一些第三方都在致力于开发一站式的开发工具,例如[Nuclide IDE]( Nuclide ), [Deco Sofeware]( Deco - React Native IDE ),但无论怎么说,我们还是探究一下各方的细节.


A. 你的移动设备 : native code 运行在上面

B. NodeJS Server : Facebook’s [Packager]( github.com/facebook/rea ) NodeJS Server. 一个类WebPack的项目,有个基于 CommonJS 的模块系统, 和一堆可用的黑科技.用来帮助 React Native 开发

C. Chrome 浏览器 : 这个不用介绍了吧

D. React Native JavaScript code : 你的价值体现


那么究竟在 Debugging 时发生了什么


Step 1: Start Packager


如果你在命令行中输入: “npm start”. 那么他会触发 react-native/local-cli/cli.js 去执行start.这个在 项目的package.json 中可以看到. 包括在XCode > Build Phases > React-Native shell > react-native-xcode.sh 最后执行的也是 cli.js. 然后他会起一个 NodeJS Server,基于 Connect 开发的.


顺序是这样的


  1. Packager 打包好并host localhost:8081/index.io
  2. packager 触发 localhost:8081/launch-c
  3. chrome打开 localhost:8081/debugger


[Terminal 中的呈现]


同时 Packager 会配置一个 WebSocket 的服务,这个稍后介绍.

tips: webSocket 是附着在http协议上的. http://localhost:8081 ws://localhost:8081


Step 2: Run React Native App in Simulator


在XCode中 run,然后模拟器中会呈现. 实测是这样的, 跳过Step 1.直接在Xcode中run,系统会自动默认的Terminal,然后跑 npm start. 在真机调试一样也会启动.


程序跑起来了



真机调试 Tip: 在用真机的时候,ws 服务的地址要换成 笔记本的IP,不能用localhost

要不iOS设备在Wifi环境下访问不到 ws服务.


一旦App在设备上跑起来,他会去访问 localhost.com:8081/inde . 并把它转换成原生的代码执行. 想看React Native原理可以参考


Packager 是跑在本地的,一旦他收到浏览器或者App的请求,他会使用Babel和Facebook自家的grapher 去collect,concat,transplie and modularize,你的 React Native JavaScript (D) 代码编程一个 response. 所以当你改动代码并保存的时候你会看到 Terminal 中会重新 transforming.


Packager process




访问 localhost:8081/index.io , 看一下package之后的代码


当iOS设备收到代码的时候, 它会把JavaScript 代码放到 Apple’s JavaScript Code 中去执行.


Step 3: Turn on Debugging Mode


现在App在设备上正常的跑着,下一步就是进入 debug 模式,这样就可以通过Chrome的webSocket inspector 去查看 React Native 编译过的版本 和 未编译版本 之前传输的数据了.


Chrome webSocket inspector



在模拟器上按 Command+D.会弹出调试选项.真机调试的时候摇一摇也会出现


React Native’s on-screen Developer menu



当你点击Debug in Chrome 的时候,客户端会发起一个请求 localhost:8081/launch-c .然后Packager会接到这个请求,然后通过 sindresorhus/opn 执行两个操作.


第一: 打开Chrome 的一个tab

第二: 让这个tab打开URL localhost:8081/debugger


Debug in Chrome process



Step 4: Debugger-ui.html and Device establish a connection


现在我们有了一个Chrome Tab,url 是 localhost:8081/debugger 这个页面的静态文件是debugger-ui.html.这个网页会有一个请求里通过. websocket 和 Packager 保持通讯.



你的App会发送3个WebSocket ping到你的Chrome. 如果Chrome反馈给你 expectedId/sessionId,那么链接将会马上建立.否则设备会抛出一个红屏”Runtime is not ready”.相信做过React Native 开发的对这个红屏不会陌生.一般 Command+R 一下就可以解决.你的App和浏览器之前的交互中间都会经过 NodeJSServer.因为http和ws服务都是他运行的.


Step 5: Execute Application Script


链接建立之后.App将会发送 WebSocket 消息到浏览器,去加载 JavaScript code.



发送的这个消息非常有意思,发送的时候回注入一个字典.字典中有很多 module/method/id 的映射关系.这里的module/method 就对应RCTModule 和 RCTMethod. 这个字典在chrome中也有体现(下图).一个真实项目中的字典可以参见附录A


这个启动消息被运行在Chrome的debugger-ui接受到.消息被插接之后放入Chrome的window对象的“__fbBatchedBridgeConfig”属性中.


[chrome 中的 window.__fbBatchedBridgeConfig]



当Chrome的window对象更新完之后.浏览器会加载 bundlejs.

然后debuggerWorker 会吧bundlejs+sourcemap 再还原成一个一个的文件供我们debug,在chrome中可以用 Command+P 来定位文件



Execute flow
debuggerWorker sourcemap



从上图可以看出,App和Chrome之间的交互离不开Packager,最后Chrome中的网页会告知executeApplicationScript webSocket消息已经发出



Step 6: Run


当 executeApplicationScript 被设备成功接受到之后.App就会重新加载js,呈现给我们.感觉Chrome和App之间通过WebSocket通信,屌屌的. 至此你可以在Chrome像调试网页的JS一样调试ReactNative的js了.不过请注意很多第三方node_module的东西无法console出来.就算是在下断点的时候.比如lodash,具体原因不清.



结语


令人值得称道的一点是, React Native js在Chrome中的运行方式和 React Native js在设备上 JavaScriptCore 的运行方式很像.都是有个 Module和method的巨大的映射表.


例如 window.__fbBatchedBridgeConfig 在设备上也有类似的mapping.这个相似点很棒.这给我们提供可一种观察JavaScriptCore的方案.


希望本文能够帮你更好的理解 React Native, 并写出更好的应用.


附录和其他


import MessageQueue from 'react-native/Libraries/BatchedBridge/MessageQueue'
MessageQueue.spy(true);


接下来会继续翻译和撰写更多的原理方面的文章.

编辑于 2018-01-02 13:18

文章被以下专栏收录