首页 > 其他分享 >React Native原理

React Native原理

时间:2022-10-13 18:23:36浏览次数:51  
标签:bridge moduleName self js React 原理 bundleURL AppRegistry Native

首先来讲一下,我们必须清楚React Native本质是使用React的思想

只不过React渲染的是真实的Dom,而React Native是使用虚拟Dom通过桥接调用原生的渲染

下面就从index.js的

AppRegistry.registerComponent到AppRegistry.runApplication来分析下程序运行的原理

几个核心概念

1、AppRegistry

   RN程序入口,相当于main函数

2、RCTRootView

   1、创建RCTBridge

   2、初始化视图 ,监听RCTJavaScriptDidLoadNotification通知,执行AppRegistry.runApplication

3、RCTBridge(主要是其父类RCTCxxBridge在操作)

   使用了多线程

4、ModuleRegistry

   模块注册,js通过他查找资源

5、GCD

  1、创建RCTBridge(NativeToJSBridge JSToNativeBridge ModuleRegistry),

  2、加载js

  3、(group_notify)前两者完成后发出资源加载完成通知RCTJavaScriptDidLoadNotification)

6、RCTJavaScriptDidLoadNotification

  资源加载完成,桥接创建好之后发送执行程序通知(AppRegistry.runApplication)

备注:

1、创建了两条线程

js线程 执行js 创建bridge

jsmessage线程 js原生通信 NativeToJSBridge JSToNativeBridge

2、模块注册

ModuleRegistry

3、多线程

dispatch_group

4、通知

执行程序通知,目的是调用AppRegistry.runApplication

大致流程图

 

 

React Native

index.js

AppRegistry.registerComponent(appName, () => App);

AppRegistry 是运行所有 React Native 应用程序的 JS 入口点。

应用程序根组件需要通过 AppRegistry.registerComponent 来注册它们自身,

然后本地系统就可以加载应用程序的包,

准备就绪后会自动调用AppRegistry.runApplication就可以真正的运行该应用程序了。

 * `AppRegistry` is the JS entry point to running all React Native apps.  App

 * root components should register themselves with

 * `AppRegistry.registerComponent`, then the native system can load the bundle

 * for the app and then actually run the app when it's ready by invoking

 * `AppRegistry.runApplication`.

iOS端

RCTRootView *rootView =
    [[RCTRootView alloc] initWithBundleURL: jsCodeLocation
                                moduleName: sBundleView
                         initialProperties:
     @{
       @"initapp" : structjson
       }
                             launchOptions: nil];
    
    
    self.view = rootView;
React Native库
RCTRootView
- (instancetype)initWithBundleURL:(NSURL *)bundleURL
                       moduleName:(NSString *)moduleName
                initialProperties:(NSDictionary *)initialProperties
                    launchOptions:(NSDictionary *)launchOptions
{
// 创建RCTBridge 内部通过父类RCTCxxBridge(C++)创建
// NativeToJSBridge JSToNativeBridge ModuleRegistry 加载执行js资源都在该方法完成
// 会发出js资源加载完成的通知RCTJavaScriptDidLoadNotification
  RCTBridge *bridge = [[RCTBridge alloc] initWithBundleURL:bundleURL
                                            moduleProvider:nil
                                             launchOptions:launchOptions];
// 初始化视图
// 最终在这个方法中调用runApplication,即index.js中的自动调用AppRegistry.runApplication
// 本质是监听资源加载完成的通知,此通知发出时说明一切都已准备好
// 会监听RCTJavaScriptDidLoadNotification通知,然后调用runApplication,即AppRegistry.runApplication()
  return [self initWithBridge:bridge moduleName:moduleName initialProperties:initialProperties];
}
//初始化视图
- (instancetype)initWithBridge:(RCTBridge *)bridge
                    moduleName:(NSString *)moduleName
             initialProperties:(NSDictionary *)initialProperties
{
  RCTAssertMainQueue();
  RCTAssert(bridge, @"A bridge instance is required to create an RCTRootView");
  RCTAssert(moduleName, @"A moduleName is required to create an RCTRootView");

  RCT_PROFILE_BEGIN_EVENT(RCTProfileTagAlways, @"-[RCTRootView init]", nil);
  if (!bridge.isLoading) {
    [bridge.performanceLogger markStartForTag:RCTPLTTI];
  }

  if (self = [super initWithFrame:CGRectZero]) {
    self.backgroundColor = [UIColor whiteColor];

    _bridge = bridge;
    _moduleName = moduleName;
    _appProperties = [initialProperties copy];
    _loadingViewFadeDelay = 0.25;
    _loadingViewFadeDuration = 0.25;
    _sizeFlexibility = RCTRootViewSizeFlexibilityNone;

    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(bridgeDidReload)
                                                 name:RCTJavaScriptWillStartLoadingNotification
                                               object:_bridge];
//  监听资源加载完成通知RCTJavaScriptDidLoadNotification 调用javaScriptDidLoad方法
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(javaScriptDidLoad:)
                                                 name:RCTJavaScriptDidLoadNotification
                                               object:_bridge];

    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(hideLoadingView)
                                                 name:RCTContentDidAppearNotification
                                               object:self];

#if TARGET_OS_TV
    self.tvRemoteHandler = [RCTTVRemoteHandler new];
    for (NSString *key in [self.tvRemoteHandler.tvRemoteGestureRecognizers allKeys]) {
      [self addGestureRecognizer:self.tvRemoteHandler.tvRemoteGestureRecognizers[key]];
    }
#endif

    [self showLoadingView];

    // Immediately schedule the application to be started.
    // (Sometimes actual `_bridge` is already batched bridge here.)
    [self bundleFinishedLoading:([_bridge batchedBridge] ?: _bridge)];
  }

  RCT_PROFILE_END_EVENT(RCTProfileTagAlways, @"");

  return self;
}
- (void)javaScriptDidLoad:(NSNotification *)notification
{
  RCTAssertMainQueue();

  // Use the (batched) bridge that's sent in the notification payload, so the
  // RCTRootContentView is scoped to the right bridge
  RCTBridge *bridge = notification.userInfo[@"bridge"];
  if (bridge != _contentView.bridge) {
    [self bundleFinishedLoading:bridge];
  }
}

- (void)bundleFinishedLoading:(RCTBridge *)bridge
{
  RCTAssert(bridge != nil, @"Bridge cannot be nil");
  if (!bridge.valid) {
    return;
  }

  [_contentView removeFromSuperview];
  _contentView = [[RCTRootContentView alloc] initWithFrame:self.bounds
                                                    bridge:bridge
                                                  reactTag:self.reactTag
                                            sizeFlexiblity:_sizeFlexibility];
  //    运行程序
  [self runApplication:bridge];

  _contentView.passThroughTouches = _passThroughTouches;
  [self insertSubview:_contentView atIndex:0];

  if (_sizeFlexibility == RCTRootViewSizeFlexibilityNone) {
    self.intrinsicContentSize = self.bounds.size;
  }
}

//运行程序 AppRegistry.runApplication()
- (void)runApplication:(RCTBridge *)bridge
{
  NSString *moduleName = _moduleName ?: @"";
  NSDictionary *appParameters = @{
    @"rootTag": _contentView.reactTag,
    @"initialProps": _appProperties ?: @{},
  };

  RCTLogInfo(@"Running application %@ (%@)", moduleName, appParameters);
  [bridge enqueueJSCall:@"AppRegistry"
                 method:@"runApplication"
                   args:@[moduleName, appParameters]
             completion:NULL];
}
RCTBridge
//1
- (instancetype)initWithBundleURL:(NSURL *)bundleURL
                   moduleProvider:(RCTBridgeModuleListProvider)block
                    launchOptions:(NSDictionary *)launchOptions
{
  return [self initWithDelegate:nil
                      bundleURL:bundleURL
                 moduleProvider:block
                  launchOptions:launchOptions];
}
//2
- (instancetype)initWithDelegate:(id<RCTBridgeDelegate>)delegate
                       bundleURL:(NSURL *)bundleURL
                  moduleProvider:(RCTBridgeModuleListProvider)block
                   launchOptions:(NSDictionary *)launchOptions
{
//
  if (self = [super init]) {
    _delegate = delegate;
    _bundleURL = bundleURL;
    _moduleProvider = block;
    _launchOptions = [launchOptions copy];
//
    [self setUp];
  }
  return self;
}
- (void)setUp
{
  RCT_PROFILE_BEGIN_EVENT(0, @"-[RCTBridge setUp]", nil);

  _performanceLogger = [RCTPerformanceLogger new];
  [_performanceLogger markStartForTag:RCTPLBridgeStartup];
  [_performanceLogger markStartForTag:RCTPLTTI];

  Class bridgeClass = self.bridgeClass;

  #if RCT_DEV
  RCTExecuteOnMainQueue(^{
    RCTRegisterReloadCommandListener(self);
  });
  #endif

  // Only update bundleURL from delegate if delegate bundleURL has changed
  NSURL *previousDelegateURL = _delegateBundleURL;
  _delegateBundleURL = [self.delegate sourceURLForBridge:self];
  if (_delegateBundleURL && ![_delegateBundleURL isEqual:previousDelegateURL]) {
    _bundleURL = _delegateBundleURL;
  }

  // Sanitize the bundle URL
  _bundleURL = [RCTConvert NSURL:_bundleURL.absoluteString];
  //  弱引用父类 RCTCxxBridge
  self.batchedBridge = [[bridgeClass alloc] initWithParentBridge:self];
  //  RCTCxxBridge
  [self.batchedBridge start];

  RCT_PROFILE_END_EVENT(RCTProfileTagAlways, @"");
}

RCTCxxBridge
- (void)start
{
  RCT_PROFILE_BEGIN_EVENT(RCTProfileTagAlways, @"-[RCTCxxBridge start]", nil);

  [[NSNotificationCenter defaultCenter]
    postNotificationName:RCTJavaScriptWillStartLoadingNotification
    object:_parentBridge userInfo:@{@"bridge": self}];

//    创建js线程
  // Set up the JS thread early
  _jsThread = [[NSThread alloc] initWithTarget:[self class]
                                      selector:@selector(runRunLoop)
                                        object:nil];
  _jsThread.name = RCTJSThreadName;
  _jsThread.qualityOfService = NSOperationQualityOfServiceUserInteractive;
#if RCT_DEBUG
  _jsThread.stackSize *= 2;
#endif
  [_jsThread start];
//  多线程 dispatch_group 创建队列组prepareBridge
//  1、初始化bridge ensureOnJavaScriptThread
//  2、加载资源 loadSource
  dispatch_group_t prepareBridge = dispatch_group_create();

  [_performanceLogger markStartForTag:RCTPLNativeModuleInit];
//  注册module 包括我们原生导出的模块RCTBridgeModule协议 RCT_EXTERN宏导出的
  [self registerExtraModules];
  // Initialize all native modules that cannot be loaded lazily
  (void)[self _initializeModules:RCTGetModuleClasses() withDispatchGroup:prepareBridge lazilyDiscovered:NO];
  [self registerExtraLazyModules];

  [_performanceLogger markStopForTag:RCTPLNativeModuleInit];

  // This doesn't really do anything.  The real work happens in initializeBridge.
//    react实例对象
  _reactInstance.reset(new Instance);

  __weak RCTCxxBridge *weakSelf = self;

  // Prepare executor factory (shared_ptr for copy into block)
//    创建执行js的工厂方法 指定js引擎
  std::shared_ptr<JSExecutorFactory> executorFactory;
  if (!self.executorClass) {
    if ([self.delegate conformsToProtocol:@protocol(RCTCxxBridgeDelegate)]) {
      id<RCTCxxBridgeDelegate> cxxDelegate = (id<RCTCxxBridgeDelegate>) self.delegate;
      executorFactory = [cxxDelegate jsExecutorFactoryForBridge:self];
    }
    if (!executorFactory) {
      executorFactory = std::make_shared<JSCExecutorFactory>(nullptr);
    }
  } else {
    id<RCTJavaScriptExecutor> objcExecutor = [self moduleForClass:self.executorClass];
    executorFactory.reset(new RCTObjcExecutorFactory(objcExecutor, ^(NSError *error) {
      if (error) {
        [weakSelf handleError:error];
      }
    }));
  }

  // Dispatch the instance initialization as soon as the initial module metadata has
  // been collected (see initModules)
  //    初始化bridge
  dispatch_group_enter(prepareBridge);
  [self ensureOnJavaScriptThread:^{
    [weakSelf _initializeBridge:executorFactory];
    dispatch_group_leave(prepareBridge);
  }];

  // Load the source asynchronously, then store it for later execution.
  //  加载资源 RCTJavaScriptLoader加载器
  dispatch_group_enter(prepareBridge);
  __block NSData *sourceCode;
  [self loadSource:^(NSError *error, RCTSource *source) {
    if (error) {
      [weakSelf handleError:error];
    }

    sourceCode = source.data;
    dispatch_group_leave(prepareBridge);
  } onProgress:^(RCTLoadingProgress *progressData) {
#if RCT_DEV && __has_include("RCTDevLoadingView.h")
    // Note: RCTDevLoadingView should have been loaded at this point, so no need to allow lazy loading.
    RCTDevLoadingView *loadingView = [weakSelf moduleForName:RCTBridgeModuleNameForClass([RCTDevLoadingView class])
                                       lazilyLoadIfNecessary:NO];
    [loadingView updateProgress:progressData];
#endif
  }];

  // Wait for both the modules and source code to have finished loading
//    多线程结束 bridge创建完成 资源加载完成
  dispatch_group_notify(prepareBridge, dispatch_get_global_queue(QOS_CLASS_USER_INTERACTIVE, 0), ^{
    RCTCxxBridge *strongSelf = weakSelf;
    if (sourceCode && strongSelf.loading) {
//        执行代码
      [strongSelf executeSourceCode:sourceCode sync:NO];
    }
  });
  RCT_PROFILE_END_EVENT(RCTProfileTagAlways, @"");
}
//初始化Bridage 在之前创建的js线程
- (void)_initializeBridge:(std::shared_ptr<JSExecutorFactory>)executorFactory
{
  if (!self.valid) {
    return;
  }

  RCTAssertJSThread();
  __weak RCTCxxBridge *weakSelf = self;
//    jsmessage js通信线程 用于跟js通讯 NativeToJSBridge JSToNativeBridge都在这个线程
  _jsMessageThread = std::make_shared<RCTMessageThread>([NSRunLoop currentRunLoop], ^(NSError *error) {
    if (error) {
      [weakSelf handleError:error];
    }
  });

  RCT_PROFILE_BEGIN_EVENT(RCTProfileTagAlways, @"-[RCTCxxBridge initializeBridge:]", nil);
  // This can only be false if the bridge was invalidated before startup completed
  if (_reactInstance) {
#if RCT_DEV
    executorFactory = std::make_shared<GetDescAdapter>(self, executorFactory);
#endif
// 初始化Bridage核心方法 NativeToJSBridge JSToNativeBridge ModuleRegistry都在该方法完成
    [self _initializeBridgeLocked:executorFactory];

#if RCT_PROFILE
    if (RCTProfileIsProfiling()) {
      _reactInstance->setGlobalVariable(
        "__RCTProfileIsProfiling",
        std::make_unique<JSBigStdString>("true"));
    }
#endif
  }

  RCT_PROFILE_END_EVENT(RCTProfileTagAlways, @"");
}
//jsMessageThread NativeToJSBridge JSToNativeBridge ModuleRegistry
- (void)_initializeBridgeLocked:(std::shared_ptr<JSExecutorFactory>)executorFactory
{
  std::lock_guard<std::mutex> guard(_moduleRegistryLock);

  // This is async, but any calls into JS are blocked by the m_syncReady CV in Instance
// initializeBridge是在之前创建的线程执行的
//  创建ModuleRegistry(映射表,原生模块要映射到js,可以理解为对应表) 并返回给_reactInstance
// _reactInstance利用ModuleRegistry,_jsMessageThread
//  创建nativeToJSBridge对象(后续原生向js发送消息主要靠他),
//  NativeToJSBridge初始化的时候顺便把JSToNativeBridge也初始化了(后学js向原生发消息主要靠他),
//  至此NativeToJSBridge JSToNativeBridge  通信(在_jsMessageThread线程)渠道打通
//  通信、映射表全部给了_reactInstance 至此初始化bridge完成
  _reactInstance->initializeBridge(
                                   std::make_unique<RCTInstanceCallback>(self),
                                   executorFactory,
                                   _jsMessageThread,
                                   [self _buildModuleRegistryUnlocked]);
  _moduleRegistryCreated = YES;
}
//回到主线程 发出RCTJavaScriptDidLoadNotification通知,
- (void)executeSourceCode:(NSData *)sourceCode sync:(BOOL)sync
{
  // This will get called from whatever thread was actually executing JS.
  dispatch_block_t completion = ^{
    // Log start up metrics early before processing any other js calls
    [self logStartupFinish];
    // Flush pending calls immediately so we preserve ordering
    [self _flushPendingCalls];

    // Perform the state update and notification on the main thread, so we can't run into
    // timing issues with RCTRootView
    dispatch_async(dispatch_get_main_queue(), ^{
//        发出RCTJavaScriptDidLoadNotification
      [[NSNotificationCenter defaultCenter]
       postNotificationName:RCTJavaScriptDidLoadNotification
       object:self->_parentBridge userInfo:@{@"bridge": self}];

      // Starting the display link is not critical to startup, so do it last
      [self ensureOnJavaScriptThread:^{
        // Register the display link to start sending js calls after everything is setup
        [self->_displayLink addToRunLoop:[NSRunLoop currentRunLoop]];
      }];
    });
  };

  if (sync) {
    [self executeApplicationScriptSync:sourceCode url:self.bundleURL];
    completion();
  } else {
    [self enqueueApplicationScript:sourceCode url:self.bundleURL onComplete:completion];
  }

#if RCT_DEV
  if (self.devSettings.isHotLoadingAvailable && self.devSettings.isHotLoadingEnabled) {
    NSString *path = [self.bundleURL.path substringFromIndex:1]; // strip initial slash
    NSString *host = self.bundleURL.host;
    NSNumber *port = self.bundleURL.port;
    [self enqueueJSCall:@"HMRClient"
                 method:@"enable"
                   args:@[@"ios", path, host, RCTNullIfNil(port)]
             completion:NULL];  }
#endif
}

 

标签:bridge,moduleName,self,js,React,原理,bundleURL,AppRegistry,Native
From: https://www.cnblogs.com/lijianyi/p/16789205.html

相关文章

  • 一文读懂 HugePages(大内存页)的原理
    在介绍HugePages之前,我们先来回顾一下Linux下虚拟内存与物理内存之间的关系。物理内存:也就是安装在计算机中的内存条,比如安装了2GB大小的内存条,那么物理内存......
  • MySQL——锁的类型以及加锁原理、死锁
    前言使用insertintoonduplicatekeyupdate语句进行插入去重,但是在测试过程中发现了死锁现象:ERROR1213(40001):Deadlockfoundwhentryingtogetlock;tryre......
  • c++ dynamic_cast 实现原理
    gcc__dynamic_cast(constvoid*src_ptr,//对象指针const__class_type_info*src_type,//源类型const__class_type_info*d......
  • Native library (win32-x86-64/xxx.dll) not found in resource path
    在本地环境启动程序遇到问题,报错信息如下Constructorthrewexception;nestedexceptionisjava.lang.UnsatisfiedLinkError:Unabletoloadlibrary'xxx':Nativeli......
  • PCA主成分分析原理与基础知识
    笔记的主要内容是PCA(主成分分析)原理和基本知识,相关数学原理和核心概念。什么是PCA分析?主成分分析(PCA,principalcomponentanalysis)是一种数学降维方法,利用正交......
  • 飞畅科技关于网管型环网交换机的工作原理介绍
    现如今,随着通信产业的发展和国民经济信息化的发展,管理型环网交换机市场稳步增长。它的成本效益高,高度灵活性,相对简单并且易于实施。以太网技术已成为当今重要的LAN网络技......
  • 一文详解IMU模型原理和标定选型
    ......
  • ThreadLocal原理及使用场景
    ​ThreadLocal意为线程本地变量,用于解决多线程并发时访问共享变量的问题。​所谓的共享变量指的是在堆中的实例、静态属性和数组;对于共享数据的访问受Java的内存模型(JMM......
  • React Hook :context上下文
    context1.Context被翻译为上下文,在编程领域,这是一个经常会接触到的概念,React中也有:InSomeCases,youwanttopassdatathroughthecomponenttreewithouthaving......
  • 09-01 简述DNS服务器原理,并搭建主-辅服务器
    简述DNS服务器原理,并搭建主-辅服务器1.DNS服务器原理1.1DNS是什么DNS(DomainNameService)的作用就是根据域名查询IP地址的方式DNS查询类型对于客户端来说是递归查询,对......