【问题标题】:In the React Native codebase, where's the code generating the claimed "single JSON message"?在 React Native 代码库中,生成声称的“单个 JSON 消息”的代码在哪里?
【发布时间】:2018-11-25 04:06:29
【问题描述】:

2018 post 中,Facebook 工程师声称:

React Native 旨在返回一条列出要执行的突变的 JSON 消息,例如 [["createView", attrs], ["manageChildren", ...]]。我们将整个系统设计为从不依赖于获取同步响应,并确保该列表中的所有内容都可以完全序列化为 JSON 并返回。

React Native codebase* 中的哪个位置是负责此功能(构建 JSON)的确切代码? 或者引用的声明可能是 谎言 “简化”?

我拼命想找到它,但似乎在绕圈子;每当我发现一首最初看起来很有希望的曲目时,它似乎永远无法将我带到生成此类 JSON 的地方:(

*请注意,我对 Android 代码库特别感兴趣;理想情况下,RN v0.55,即撰写本文时的最新版本。

如果可能的话,我也对互补的“反向”代码感兴趣。我的意思是,我假设“本机”(Android 的情况下是 Java)代码还必须在某个时候将一些“事件”信号发送回 JS,并且我假设它们也是 JSON。那么,再一次,这段代码在哪里? (我对接收和反序列化该 JSON 的 JS 代码感兴趣。)

(另外,我非常感谢了解这些“低级”功能(发送和接收 JSON)是否可以在基于 Expo 的应用程序中以原始形式从 JS 访问;但这是100% 的答案是可选的,因为我有理由相信,一旦我知道上述主要问题的答案,我就能自己找出答案。)

注意:为了全面披露,我还交叉发布了这个问题on HN,但截至发稿时还没有答案。我计划在 HN 上的讨论帖过时时从此处删除此注释。

编辑1号

基于a "Related" question suggested by SO,我开始有一种模糊的感觉,即名为“BatchedBridge”的概念/关键字可能与我正在寻找的内容非常接近。我的直觉似乎告诉我,这可能是朝着正确方向迈出的第一步。我发现了一篇描述 how to observe messages flying both ways through BatchedBridge 的博客文章,据报道导致日志如下:

{type: 1, module: "WebSocketModule", method: "addListener", args: Array(1)}
{type: 1, module: "WebSocketModule", method: "connect", args: Array(4)}
{type: 0, module: "RCTDeviceEventEmitter", method: "emit", args: Array(2)}
{type: 1, module: "Timing", method: "createTimer", args: Array(4)}

同一博客上的另一篇文章显示了如何send events from Java to JS over this "bridge", and listen to them in JS。这可以回答我问题的最后一个可选部分的一半,关于如何在 Expo 中从 JS 订阅 Java 事件。 (Java 中:this.reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit("onSessionConnect", params);,JS 中:DeviceEventEmitter.addListener('onSessionConnect', (event) => { console.log(event); });

另一个有趣的article on RN internals,来自使用“react-native BatchedBridge”作为关键字进行谷歌搜索。

编辑 2,暂定

构建 JSON 的地方可能line 556 below,虽然我不太确定:

550 void JSCExecutor::callNativeModules(Value&& value) {
...
556   auto calls = value.toJSONString();
557   m_delegate->callNativeModules(*this, folly::parseJson(calls), true);

称为例如from l.642 below:

624 void JSCExecutor::invokeCallback(
625     const double callbackId,
626     const folly::dynamic& arguments) {
...
628   auto result = [&] {
...
634       return m_invokeCallbackAndReturnFlushedQueueJS->callAsFunction(
635           {Value::makeNumber(m_context, callbackId),
636            Value::fromDynamic(m_context, std::move(arguments))});
...
642   callNativeModules(std::move(result));

【问题讨论】:

    标签: react-native


    【解决方案1】:

    根据问题中链接的文章,以及2015年的somevideos,经过一天的挖掘,我相信确实是BatchedBridge,又名MessageQueue,也就是公共汽车用于 Java/Swift 和 JS 之间的调用。

    如果我理解正确,JS->Java 调用是用MessageQueue.enqueueNativeCall 完成的,定义为:

      enqueueNativeCall(
        moduleID: number,
        methodID: number,
        params: any[],
        onFail: ?Function,
        onSucc: ?Function,
      )
    

    Java->JS 调用是通过以下任一函数完成的(在同一文件中):

    callFunctionReturnFlushedQueue(module: string, method: string, args: any[])
    callFunctionReturnResultAndFlushedQueue(module: string, method: string, args: any[])
    invokeCallbackAndReturnFlushedQueue(cbID: number, args: any[])
    

    这仍然没有真正回答“JSON 在哪里?”的问题,但实际上我更感兴趣的是找到总线并验证流经它的是否是 JSON。虽然我现在甚至不确定它最终是否会具体化为实际的 JSON 字符串,但我相信它至少是“意识形态上的”JSON。 MessageQueue IIUC 上似乎不允许非 JSON 兼容的对象,我相信“函数指针/回调”已转换为函数名称,以便可以从 Java 异步调用它们。我相信函数结果会被忽略(即所有 JS 函数都假定有 void 返回类型)。

    edit:callFunctionReturnResultAndFlushedQueue 似乎返回了 JS 函数的结果,所以它看起来必须是非异步的(阻塞)。但是在搜索了 m_callFunctionReturnResultAndFlushedQueueJScallFunctionReturnResultAndFlushedQueue 的 react-native repo 之后,似乎没有一个是从任何地方调用的。在 C++ 中你永远无法 100% 确定,但现在我要祈祷并假设它可以被安全地忽略。

    【讨论】:

    • 大家好,我是帖子作者。我相信,您在 JSCExecutor 中引用的那一行是序列化为 JSON 的那一行。可能是我记错了,从 JS 返回的结果永远不会变成 JSON(与来自本地的命令相反,肯定会),但它在某一时刻确实如此,而且我们没有放宽任何限制,正如您所注意到的。我们会的。
    • @SophieAlpert Woohoo,很酷的插话,感谢您的确认! :D
    猜你喜欢
    • 1970-01-01
    • 2017-09-20
    • 1970-01-01
    • 2022-08-09
    • 2011-02-09
    • 1970-01-01
    • 1970-01-01
    • 2018-06-19
    • 1970-01-01
    相关资源
    最近更新 更多