React Native 原理浅析

0.简介

先说下了解这个有啥好处吧

  1. 有利于使用原生平台提供的更多的功能和API,或者接入第三方的库和服务,比如接入阿里的服务。
  2. 知道性能开销在哪,能针对的优化你的代码提高性能。
  3. debug,知道的越多当然更容易知道问题为什么出现了
  4. 更好的回答面试官的问题 😂😂

然后开始吧,RN的架构分为三块,js的部分,原生Native的部分,和连接这两者的桥Bridge。

以下为架构示意图
架构示意图

1. JavaScript线程

这是一个单独的线程,用来运行JavaScript代码,包括React组件的渲染逻辑,业务逻辑,事件处理等。JavaScript线程使用JavaScript引擎来执行代码,比如Hermes或者JSCore。

1.1 JavaScript引擎

JavaScript引擎是一个负责解析和执行JavaScript代码的模块。不同的JavaScript引擎有不同的性能和特性,比如Chrome用的是V8,Firefox用的是SpiderMonkey,Safari用的是JSCore。

而React Native则有两种选择,JSCore和Hermes。
JSCore兼容性更好,Hermes则性能更好更小(RN出品的)。
React Native默认使用JSCore,但是你也可以自己配置下,改成Hermes,

如果想深入了解可以看这两篇文章
1. React Native Memory profiling (JSC vs V8 vs Hermes)
2. 使用新的 Hermes 引擎 - react native

1.2 JavaScript代码

最熟悉的部分了,就你项目里的js代码了,包括React组件的渲染,业务逻辑,事件处理等。如果你已经做过RN的开发,那你会发现你可以用js的库,比如Typescript / Redux,当然了,也不是全部都能用,有一些不适配RN。

JS可以通过Bridge调用Native的方法函数,也能通过Bridge接收Native的消息。

2. Native线程

这个线程用来运行原生平台的代码,包括UI渲染,动画等。Native线程使用原生平台的语言和技术来执行代码,iOS是Objective-C或者Swift,而Android则是Java或者Kotlin。

2.1 原生平台

原生平台是指运行React Native应用的操作系统和设备,比如iOS平台和iPhone设备,Android平台和华为小米设备等。原生平台提供了一些基础的功能和API,比如视图(View),文本(Text),图像(Image),按钮(Button),滚动视图(ScrollView),列表视图(ListView)等。这些功能和API可以被React Native封装成对应的React组件,并通过Bridge暴露给JavaScript线程。
所以,我们在写RN时import RN的 View Text,在IOS渲染用的就是IOS的组件,在安卓机渲染时用的就是安卓的组件。

原生平台也提供了一些高级的功能和API,比如相机(Camera),定位(Geolocation),剪贴板(Clipboard)等。这些功能和API被React Native封装成Native模块,并通过Bridge注册和导出给JavaScript线程。

2.2 原生代码

原生代码在Native线程中执行,并通过Bridge与JS线程通信。原生代码可以接收JS线程发送过来的数据和命令,并执行相应的操作。也可以写一些原生的代码,在需要的时候通过Bridge传递给JS线程,说的有点抽象,懂的自然懂。

3. Bridge

这是一个中间层,用来连接JavaScript线程和Native线程,实现数据和命令的传递和处理。Bridge使用序列化和反序列化的方式来编码和解码消息,并使用消息队列来缓存和发送消息。

Bridge是异步多,不会阻塞任何一方的执行,但消息多了也会影响性能。

同时也是一个单向的,它只能从一方向另一方发送消息,而不能同时进行双向通信。所以需要一种协议来规范消息的格式和含义,以及一种机制来实现回调和错误处理。

3.1 消息格式

Bridge传递消息用的是JSON。

这个消息JSON长这样。

{
  "module": "Camera",
  "method": "takePicture",
  "args": [true, 0.8],
  "callbackId": 1
}

解释一下
这个消息表示JavaScript线程调用了Camera模块的takePicture方法,并传递了两个参数。
同时,这个消息指定了一个回调ID为1,表示JavaScript线程期望Native线程在执行完毕后返回结果或者错误信息。

3.2 消息队列

Bridge使用消息队列来缓存和发送消息,这是一种先进先出(FIFO)的数据结构,可以保证消息的顺序和完整性。

Bridge维护了两个消息队列:
一个用来存储JavaScript线程发送给Native线程的消息。
另一个用来存储Native线程发送给JavaScript线程的消息。

当JavaScript线程或者Native线程有新的消息要发送时,它会将消息添加到对应的消息队列中,并通知对方有新的消息可用。当对方收到通知后,它会从消息队列中取出所有的消息,并依次处理。

3.3 消息处理

Bridge使用事件驱动的方式来处理消息,这是一种基于回调函数的编程模式,它可以实现异步和非阻塞的通信。

Bridge为每个Native模块注册了一个回调函数,并将其映射到一个模块ID。
JavaScript线程调用一个Native模块时,它会通过Bridge发送一个包含模块ID,方法名,参数等信息的消息,并指定一个回调ID。
Native线程收到这个消息后,它会根据模块ID找到对应的回调函数,并执行该函数。
函数执行完毕后,它会通过Bridge发送一个包含回调ID,结果或者错误信息等信息的消息。
JavaScript线程收到这个消息后,它会根据回调ID找到对应的回调函数,并执行该函数。

4. Native模块

这是一些封装了原生平台功能的模块,可以被JavaScript线程调用,比如Camera,Geolocation,Clipboard等。

Native模块使用原生的语言来实现,并通过Bridge注册和导出给JavaScript线程。
JavaScript线程可以通过Bridge向Native模块发送请求,并接收返回值或者错误信息。
Native模块可以让JavaScript线程使用原生平台提供的功能和API。

4.1 Native模块的实现

为了便于Bridge识别和调用,Native模块需要遵循一定的规范和接口。
不同的原生平台有不同的实现方式,但是基本思路都差不多。

举个栗子🌰

// iOS平台
#import <React/RCTBridgeModule.h>

@interface RCTCameraModule : NSObject <RCTBridgeModule>
@end

@implementation RCTCameraModule

// 注册模块名
RCT_EXPORT_MODULE(Camera);

// 注册方法名
RCT_EXPORT_METHOD(takePicture:(BOOL)flash quality:(float)quality callback:(RCTResponseSenderBlock)callback)
{
  // 实现方法逻辑
  UIImage *image = ...;
  if (image) {
    // 返回结果
    callback(@[[NSNull null], image]);
  } else {
    // 返回错误
    callback(@[@"Camera error", [NSNull null]]);
  }
}

@end
// Android
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.Callback;

public class CameraModule extends ReactContextBaseJavaModule {

  public CameraModule(ReactApplicationContext reactContext) {
    super(reactContext);
  }

  // 注册模块名
  @Override
  public String getName() {
    return "Camera";
  }

  // 注册方法名
  @ReactMethod
  public void takePicture(boolean flash, float quality, Callback callback) {
    // 实现方法逻辑
    Bitmap image = ...;
    if (image != null) {
      // 返回结果
      callback.invoke(null, image);
    } else {
      // 返回错误
      callback.invoke("Camera error", null);
    }
  }
}

4.2 Native模块的调用

Native模块的调用要用RN的API。

// JavaScript
import { NativeModules } from 'react-native';

// 获取Native模块对象
const Camera = NativeModules.Camera;

// 调用Native模块方法,并传递参数和回调函数
Camera.takePicture(true, 0.8, (error, image) => {
  if (error) {
    // 处理错误
    console.error(error);
  } else {
    // 处理结果
    console.log(image);
  }
});

以上就是全部内容了,欢迎点赞转发收藏,有问题或勘误请留言,感谢。

  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值