普通视图

发现新文章,点击刷新页面。
昨天 — 2026年1月28日首页

React Native新架构之iOS端初始化源码分析

2026年1月28日 21:41

React Native新架构之iOS端初始化源码分析

前言

注意,本文是基于React Native 0.83版本源码进行分析。有了前面几篇Android端分析文章打基础,再来理解iOS端就易如反掌了。总的来说,iOS端的实现要比Android端简单太多了,这是因为Android端的Java/Kotlin 都是运行在Java的虚拟机环境中,其与C++通信要经过JNI,并不如OC与C++互调那么简单直接。此外,RN基于Android的Gradle构建机制,也使问题更加复杂。

初始化流程

React Native的iOS端相比于安卓端要简单很多。现在我们基于Swift入口来分析一下初始化流程。首先找到RN源码工程中的测试工程,打开源码react-native/private/helloworld/ios/HelloWorld/AppDelegate.swift

import React                          // React Native 核心模块
import ReactAppDependencyProvider     // Codegen 生成的依赖提供者
import React_RCTAppDelegate           // AppDelegate 相关类
import UIKit

@main
class AppDelegate: UIResponder, UIApplicationDelegate {
  var window: UIWindow?

  var reactNativeDelegate: ReactNativeDelegate?
  var reactNativeFactory: RCTReactNativeFactory?

  func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil
  ) -> Bool {
    // 1: 创建 ReactNativeDelegate
    let delegate = ReactNativeDelegate()
    // 2: 创建 RCTReactNativeFactory
    let factory = RCTReactNativeFactory(delegate: delegate)
    // 3: 配置依赖提供者(Codegen 生成的模块)
    delegate.dependencyProvider = RCTAppDependencyProvider()

    // 保持强引用
    reactNativeDelegate = delegate
    reactNativeFactory = factory

    // 4: 配置开发菜单(仅 DEBUG 模式)
    #if DEBUG
    let devMenuConfiguration = RCTDevMenuConfiguration(
      devMenuEnabled: true,
      shakeGestureEnabled: true,
      keyboardShortcutsEnabled: true
    )
    reactNativeFactory?.devMenuConfiguration = devMenuConfiguration
    #endif

    // 5: 创建主窗口
    window = UIWindow(frame: UIScreen.main.bounds)

    // 6: 启动 React Native
    factory.startReactNative(
      withModuleName: "HelloWorld",
      in: window,
      launchOptions: launchOptions
    )

    return true
  }
}

class ReactNativeDelegate: RCTDefaultReactNativeFactoryDelegate {
  // 旧架构兼容(新架构中会调用 bundleURL)
  override func sourceURL(for bridge: RCTBridge) -> URL? {
    self.bundleURL()
  }

  // 提供 JS Bundle 的 URL
  override func bundleURL() -> URL? {
    #if DEBUG
    // 开发模式:从 Metro 开发服务器加载
    RCTBundleURLProvider.sharedSettings().jsBundleURL(forBundleRoot: "index")
    #else
    // 生产模式:从 App Bundle 加载
    Bundle.main.url(forResource: "main", withExtension: "jsbundle")
    #endif
  }
}

Swift 新架构使用 @main 注解作为应用入口,无需 main.mmain.swift 文件。ReactNativeDelegate 继承自 RCTDefaultReactNativeFactoryDelegate,负责提供 Bundle URL 和自定义配置。

这里RCTAppDependencyProvider是Objective-C++代码,这是为了方便与C++互调。源码tcode/react-native/packages/react-native/Libraries/AppDelegate/RCTReactNativeFactory.mm

@interface RCTReactNativeFactory () <
    RCTComponentViewFactoryComponentProvider, // Fabric 组件提供者
    RCTHostDelegate,                          // RCTHost 代理
    RCTJSRuntimeConfiguratorProtocol,         // JS Runtime 配置
    RCTTurboModuleManagerDelegate>            // TurboModule 管理器代理
@end

@implementation RCTReactNativeFactory

- (instancetype)initWithDelegate:(id<RCTReactNativeFactoryDelegate>)delegate
{
  return [self initWithDelegate:delegate releaseLevel:Stable];
}

- (instancetype)initWithDelegate:(id<RCTReactNativeFactoryDelegate>)delegate releaseLevel:(RCTReleaseLevel)releaseLevel
{
  if (self = [super init]) {
    self.delegate = delegate;
    [self _setUpFeatureFlags:releaseLevel];
    // 设置默认颜色空间
    [RCTColorSpaceUtils applyDefaultColorSpace:[self defaultColorSpace]];
    RCTEnableTurboModule(YES);

    // 创建 RCTRootViewFactory
    self.rootViewFactory = [self createRCTRootViewFactory];
    // 设置第三方 Fabric 组件提供者
    [RCTComponentViewFactory currentComponentViewFactory].thirdPartyFabricComponentsProvider = self;
  }

  return self;
}

可以看到RCTReactNativeFactory的构造逻辑非常简单,但它实现了四个关键协议,这使得它可以作为多个子系统的代理。

先重点看一下createRCTRootViewFactory方法的实现,这是一个关键方法,同时设置了大量的回调 Block 来桥接代理模式:

- (RCTRootViewFactory *)createRCTRootViewFactory
{
  __weak __typeof(self) weakSelf = self;
  // 1. 创建 Bundle URL 提供者 Block
  RCTBundleURLBlock bundleUrlBlock = ^{
    auto *strongSelf = weakSelf;
    return strongSelf.bundleURL;
  };

  // 2. 创建配置对象(新架构默认全部启用)
  RCTRootViewFactoryConfiguration *configuration =
      [[RCTRootViewFactoryConfiguration alloc] initWithBundleURLBlock:bundleUrlBlock
                                                       newArchEnabled:YES
                                                   turboModuleEnabled:YES
                                                    bridgelessEnabled:YES];

  // 省略旧架构代码......

  // 3.配置根视图自定义回调
  configuration.customizeRootView = ^(UIView *_Nonnull rootView) {
    [weakSelf.delegate customizeRootView:(RCTRootView *)rootView];
  };

  // 4.配置 Bundle URL 获取回调
  configuration.sourceURLForBridge = ^NSURL *_Nullable(RCTBridge *_Nonnull bridge)
  {
    // 新架构:直接使用 bundleURL,不再依赖 bridge
    return [weakSelf.delegate bundleURL];
  };

  // 5.配置 Bundle 加载回调(支持进度)
  if ([self.delegate respondsToSelector:@selector(loadSourceForBridge:onProgress:onComplete:)]) {
    configuration.loadSourceForBridgeWithProgress =
        ^(RCTBridge *_Nonnull bridge,
          RCTSourceLoadProgressBlock _Nonnull onProgress,
          RCTSourceLoadBlock _Nonnull loadCallback) {
          // 新架构:使用 loadBundleAtURL 替代旧的 loadSourceForBridge
          [weakSelf.delegate loadBundleAtURL:self.bundleURL onProgress:onProgress onComplete:loadCallback];
        };
  }

  // 6.配置无进度的 Bundle 加载回调
  if ([self.delegate respondsToSelector:@selector(loadSourceForBridge:withBlock:)]) {
    configuration.loadSourceForBridge = ^(RCTBridge *_Nonnull bridge, RCTSourceLoadBlock _Nonnull loadCallback) {
      // 新架构:使用 loadBundleAtURL,进度回调为空
      [weakSelf.delegate loadBundleAtURL:self.bundleURL
                              onProgress:^(RCTLoadingProgress *progressData) {
                              }
                              onComplete:loadCallback];
    };
  }

  // 7.设置 JS Runtime 代理
  configuration.jsRuntimeConfiguratorDelegate = self;
  // 8.创建并返回 RCTRootViewFactory
  return [[RCTRootViewFactory alloc] initWithTurboModuleDelegate:self hostDelegate:self configuration:configuration];
}

这里的大概流程是非常清楚的,主要就是设置了四个协议的代理。我们将流程绘制成一个关系图:

┌─────────────────────────────────────────────────────────────────────────┐
│                        RCTReactNativeFactory                             │
│  ┌───────────────────────────────────────────────────────────────────┐  │
│  │ 实现协议:                                                          │  │
│  │  • RCTTurboModuleManagerDelegate    → TurboModule 类/实例查找      │  │
│  │  • RCTHostDelegate                  → Host 生命周期 + Bundle 加载  │  │
│  │  • RCTJSRuntimeConfiguratorProtocol → JS Runtime 工厂创建         │  │
│  │  • RCTComponentViewFactoryComponentProvider → Fabric 组件注册     │  │
│  └───────────────────────────────────────────────────────────────────┘  │
│                                    │                                     │
│                                    ▼                                     │
│  ┌───────────────────────────────────────────────────────────────────┐  │
│  │ createRCTRootViewFactory() 中设置:                                 │  │
│  │  • initWithTurboModuleDelegate: self  ← RCTTurboModuleManagerDelegate│
│  │  • hostDelegate: self                 ← RCTHostDelegate              │
│  │  • jsRuntimeConfiguratorDelegate: self ← RCTJSRuntimeConfiguratorProtocol│
│  └───────────────────────────────────────────────────────────────────┘  │
│                                    │                                     │
│                                    ▼                                     │
│  ┌───────────────────────────────────────────────────────────────────┐  │
│  │ 初始化时设置:                                                       │  │
│  │  • thirdPartyFabricComponentsProvider = self                       │  │
│  │    ← RCTComponentViewFactoryComponentProvider                      │  │
│  └───────────────────────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────────────────────┘

RCTTurboModuleManagerDelegate

主要负责 TurboModule 的类查找和实例创建,源码react-native/packages/react-native/ReactCommon/react/nativemodule/core/platform/ios/ReactCommon/RCTTurboModuleManager.h

@class RCTBridgeProxy;
@class RCTTurboModuleManager;
@class RCTDevMenuConfigurationDecorator;

@protocol RCTTurboModuleManagerDelegate <NSObject>

/**
 * 给定模块名称,返回其实际类。如果返回 nil,则执行基本的 ObjC 类查找
 */
- (Class)getModuleClassFromName:(const char *)name;

/**
 * 给定一个模块类,为其提供一个实例。如果返回值为 nil,则使用默认初始化器
 */
- (id<RCTTurboModule>)getModuleInstanceFromClass:(Class)moduleClass;

@optional

/**
 * 此方法用于获取一个工厂对象,该对象可以创建 `facebook::react::TurboModule` 实例。
 * 实现 `RCTTurboModuleProvider` 接口的类必须是 Objective-C 类,以便我们可以使用代码生成工具对其进行动态初始化。
 */
- (id<RCTModuleProvider>)getModuleProvider:(const char *)name;

/**
 * 创建一个 TurboModule 实例,而无需依赖任何 ObjC++ 模块实例
 */
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:(const std::string &)name
                                                      jsInvoker:
                                                          (std::shared_ptr<facebook::react::CallInvoker>)jsInvoker;

- (void)installJSBindings:(facebook::jsi::Runtime &)runtime;

- (void)invalidate;

@end

再来看看RCTReactNativeFactory 中的实现:

#pragma mark - RCTTurboModuleManagerDelegate

- (Class)getModuleClassFromName:(const char *)name
{
#if RN_DISABLE_OSS_PLUGIN_HEADER
  return RCTTurboModulePluginClassProvider(name);
#else
  // 先尝试从 delegate 获取
  if ([_delegate respondsToSelector:@selector(getModuleClassFromName:)]) {
    Class moduleClass = [_delegate getModuleClassFromName:name];
    if (moduleClass != nil) {
      return moduleClass;
    }
  }
  return RCTCoreModulesClassProvider(name);
#endif
}

- (nullable id<RCTModuleProvider>)getModuleProvider:(const char *)name
{
  if ([_delegate respondsToSelector:@selector(getModuleProvider:)]) {
    return [_delegate getModuleProvider:name];
  }
  return nil;
}

// 创建纯 C++ TurboModule
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:(const std::string &)name
                                                      jsInvoker:(std::shared_ptr<facebook::react::CallInvoker>)jsInvoker
{
  if ([_delegate respondsToSelector:@selector(getTurboModule:jsInvoker:)]) {
    return [_delegate getTurboModule:name jsInvoker:jsInvoker];
  }

  return facebook::react::DefaultTurboModules::getTurboModule(name, jsInvoker);
}

- (id<RCTTurboModule>)getModuleInstanceFromClass:(Class)moduleClass
{
#if USE_OSS_CODEGEN
  if (self.delegate.dependencyProvider == nil) {
    [NSException raise:@"ReactNativeFactoryDelegate dependencyProvider is nil"
                format:@"Delegate must provide a valid dependencyProvider"];
  }
#endif
  if ([_delegate respondsToSelector:@selector(getModuleInstanceFromClass:)]) {
    id<RCTTurboModule> moduleInstance = [_delegate getModuleInstanceFromClass:moduleClass];
    if (moduleInstance != nil) {
      return moduleInstance;
    }
  }
  // 使用默认方式创建(通过 dependencyProvider)
  return RCTAppSetupDefaultModuleFromClass(moduleClass, self.delegate.dependencyProvider);
}

RCTHostDelegate

主要负责 RCTHost 的生命周期和 Bundle 加载。源码react-native/packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTHost.h

NS_ASSUME_NONNULL_BEGIN

@class RCTFabricSurface;
@class RCTHost;
@class RCTModuleRegistry;
@class RCTDevMenuConfiguration;

@protocol RCTTurboModuleManagerDelegate;

typedef NSURL *_Nullable (^RCTHostBundleURLProvider)(void);

// Runtime API

@protocol RCTHostDelegate <NSObject>
// Host 启动完成通知
- (void)hostDidStart:(RCTHost *)host;

@optional
// 需要在主线程初始化的模块列表
- (NSArray<NSString *> *)unstableModulesRequiringMainQueueSetup;

// 加载 Bundle(支持进度回调)
- (void)loadBundleAtURL:(NSURL *)sourceURL
             onProgress:(RCTSourceLoadProgressBlock)onProgress
             onComplete:(RCTSourceLoadBlock)loadCallback;

@end


NS_ASSUME_NONNULL_END

查看RCTReactNativeFactory 中的实现:

#pragma mark - RCTHostDelegate

- (void)hostDidStart:(RCTHost *)host
{
  if ([_delegate respondsToSelector:@selector(hostDidStart:)]) {
    [_delegate hostDidStart:host];
  }
}

- (NSArray<NSString *> *)unstableModulesRequiringMainQueueSetup
{
#if RN_DISABLE_OSS_PLUGIN_HEADER
  return RCTTurboModulePluginUnstableModulesRequiringMainQueueSetup();
#else
  return self.delegate.dependencyProvider
      ? RCTAppSetupUnstableModulesRequiringMainQueueSetup(self.delegate.dependencyProvider)
      : @[];
#endif
}

RCTJSRuntimeConfiguratorProtocol

主要负责创建 JS Runtime 工厂,源码react-native/packages/react-native/Libraries/AppDelegate/RCTJSRuntimeConfiguratorProtocol.h

NS_ASSUME_NONNULL_BEGIN

// Forward declarations for umbrella headers.
// In implementations, import `<react/runtime/JSRuntimeFactoryCAPI.h>` to obtain the actual type.
typedef void *JSRuntimeFactoryRef;

@protocol RCTJSRuntimeConfiguratorProtocol

// 创建 JS Runtime 工厂(通常返回 Hermes)
- (JSRuntimeFactoryRef)createJSRuntimeFactory;

@end

NS_ASSUME_NONNULL_END

查看RCTReactNativeFactory 中的实现:

#pragma mark - RCTJSRuntimeConfiguratorProtocol

- (JSRuntimeFactoryRef)createJSRuntimeFactory
{
  // 委托给用户的 delegate
  return [_delegate createJSRuntimeFactory];
}

RCTComponentViewFactoryComponentProvider

主要负责提供第三方 Fabric 组件,源码react-native/packages/react-native/React/Fabric/Mounting/RCTComponentViewFactory.h

/**
 * 可用于向 Fabric 提供第三方组件的协议。
 * Fabric 将检查此映射表,以确定是否存在需要注册的组件。
 */
@protocol RCTComponentViewFactoryComponentProvider <NSObject>

/**
 * 返回一个第三方组件字典,其中 `key` 是组件处理程序,`value` 是一个符合 `RCTComponentViewProtocol` 协议的类
 */
- (NSDictionary<NSString *, Class<RCTComponentViewProtocol>> *)thirdPartyFabricComponents;

@end

查看RCTReactNativeFactory 中的实现:

#pragma mark - RCTComponentViewFactoryComponentProvider

- (NSDictionary<NSString *, Class<RCTComponentViewProtocol>> *)thirdPartyFabricComponents
{
  // 先尝试从 delegate 获取
  if ([_delegate respondsToSelector:@selector(thirdPartyFabricComponents)]) {
    return _delegate.thirdPartyFabricComponents;
  }
  // 回退到 dependencyProvider(Codegen 生成)
  return self.delegate.dependencyProvider ? self.delegate.dependencyProvider.thirdPartyFabricComponents : @{};
}

RCTDefaultReactNativeFactoryDelegate

以上协的很多方法的实现,其实也是代理给RCTReactNativeFactory 中的delegate对象。此delegate也就是我们最开始自定义的ReactNativeDelegate实例。其也是继承自RCTDefaultReactNativeFactoryDelegate,现在分析一下此类的实现,源码react-native/packages/react-native/Libraries/AppDelegate/RCTDefaultReactNativeFactoryDelegate.mm

@implementation RCTDefaultReactNativeFactoryDelegate

@synthesize dependencyProvider;
// 抽象方法:子类必须实现
- (NSURL *_Nullable)sourceURLForBridge:(nonnull RCTBridge *)bridge
{
  [NSException raise:@"RCTBridgeDelegate::sourceURLForBridge not implemented"
              format:@"Subclasses must implement a valid sourceURLForBridge method"];
  return nil;
}

- (UIViewController *)createRootViewController
{
  return [UIViewController new];
}

- (void)setRootView:(UIView *)rootView toRootViewController:(UIViewController *)rootViewController
{
  rootViewController.view = rootView;
}

- (JSRuntimeFactoryRef)createJSRuntimeFactory
{
#if USE_THIRD_PARTY_JSC != 1
  return jsrt_create_hermes_factory();
#endif
}

- (void)customizeRootView:(RCTRootView *)rootView
{
  // Override point for customization after application launch.
}

- (RCTColorSpace)defaultColorSpace
{
  return RCTColorSpaceSRGB;
}

- (NSURL *_Nullable)bundleURL
{
  [NSException raise:@"RCTAppDelegate::bundleURL not implemented"
              format:@"Subclasses must implement a valid getBundleURL method"];
  return nullptr;
}

- (NSDictionary<NSString *, Class<RCTComponentViewProtocol>> *)thirdPartyFabricComponents
{
  return (self.dependencyProvider != nullptr) ? self.dependencyProvider.thirdPartyFabricComponents : @{};
}

- (void)hostDidStart:(RCTHost *)host
{
}

- (NSArray<NSString *> *)unstableModulesRequiringMainQueueSetup
{
  return (self.dependencyProvider != nullptr)
      ? RCTAppSetupUnstableModulesRequiringMainQueueSetup(self.dependencyProvider)
      : @[];
}

- (nullable id<RCTModuleProvider>)getModuleProvider:(const char *)name
{
  NSString *providerName = [NSString stringWithCString:name encoding:NSUTF8StringEncoding];
  return (self.dependencyProvider != nullptr) ? self.dependencyProvider.moduleProviders[providerName] : nullptr;
}

- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:(const std::string &)name
                                                      jsInvoker:(std::shared_ptr<facebook::react::CallInvoker>)jsInvoker
{
  return facebook::react::DefaultTurboModules::getTurboModule(name, jsInvoker);
}

#pragma mark - RCTArchConfiguratorProtocol

- (BOOL)newArchEnabled
{
  return YES;
}

- (BOOL)bridgelessEnabled
{
  return YES;
}

- (BOOL)fabricEnabled
{
  return YES;
}

- (BOOL)turboModuleEnabled
{
  return YES;
}

- (Class)getModuleClassFromName:(const char *)name
{
  return nullptr;
}

- (id<RCTTurboModule>)getModuleInstanceFromClass:(Class)moduleClass
{
  return nullptr;
}

- (void)loadSourceForBridge:(RCTBridge *)bridge
                 onProgress:(RCTSourceLoadProgressBlock)onProgress
                 onComplete:(RCTSourceLoadBlock)loadCallback
{
  [RCTJavaScriptLoader loadBundleAtURL:[self sourceURLForBridge:bridge] onProgress:onProgress onComplete:loadCallback];
}

@end

React Native 启动

对于以上四个协议以及代理,我们已经有了大概认识,现在应该把视线拉回AppDelegate中的初始化流程,继续分析startReactNative方法的实现,它对应的OC方法名应该是startReactNativeWithModuleName

- (void)startReactNativeWithModuleName:(NSString *)moduleName
                              inWindow:(UIWindow *_Nullable)window
                         launchOptions:(NSDictionary *_Nullable)launchOptions
{
  [self startReactNativeWithModuleName:moduleName inWindow:window initialProperties:nil launchOptions:launchOptions];
}

- (void)startReactNativeWithModuleName:(NSString *)moduleName
                              inWindow:(UIWindow *_Nullable)window
                     initialProperties:(NSDictionary *_Nullable)initialProperties
                         launchOptions:(NSDictionary *_Nullable)launchOptions
{
  // 1. 通过 RootViewFactory 创建根视图
  UIView *rootView = [self.rootViewFactory viewWithModuleName:moduleName
                                            initialProperties:initialProperties
                                                launchOptions:launchOptions
                                         devMenuConfiguration:self.devMenuConfiguration];
  // 2. 创建 RootViewController
  UIViewController *rootViewController = [_delegate createRootViewController];
  // 3. 设置根视图
  [_delegate setRootView:rootView toRootViewController:rootViewController];
  // 4. 配置窗口并显示
  window.rootViewController = rootViewController;
  [window makeKeyAndVisible];
}

可以看到,流程十分清楚,我们继续跟踪viewWithModuleName方法实现。

RCTHost (ReactHost)初始化

查看源码react-native/packages/react-native/Libraries/AppDelegate/RCTRootViewFactory.mm

- (UIView *)viewWithModuleName:(NSString *)moduleName
             initialProperties:(NSDictionary *)initProps
                 launchOptions:(NSDictionary *)launchOptions
          devMenuConfiguration:(RCTDevMenuConfiguration *)devMenuConfiguration
{
  // 1. 初始化 ReactHost
  [self initializeReactHostWithLaunchOptions:launchOptions devMenuConfiguration:devMenuConfiguration];

  // 2. 创建 Fabric Surface
  RCTFabricSurface *surface = [self.reactHost createSurfaceWithModuleName:moduleName
                                                        initialProperties:initProps ? initProps : @{}];
   // 3. 创建 SurfaceHostingProxyRootView
  RCTSurfaceHostingProxyRootView *surfaceHostingProxyRootView =
      [[RCTSurfaceHostingProxyRootView alloc] initWithSurface:surface];

  surfaceHostingProxyRootView.backgroundColor = [UIColor systemBackgroundColor];
  if (_configuration.customizeRootView != nil) {
    // 4. 自定义根视图
    _configuration.customizeRootView(surfaceHostingProxyRootView);
  }
  return surfaceHostingProxyRootView;
}


- (void)initializeReactHostWithLaunchOptions:(NSDictionary *)launchOptions
                        devMenuConfiguration:(RCTDevMenuConfiguration *)devMenuConfiguration
{
  // Enable TurboModule interop by default in Bridgeless mode
  RCTEnableTurboModuleInterop(YES);
  RCTEnableTurboModuleInteropBridgeProxy(YES);

  [self createReactHostIfNeeded:launchOptions devMenuConfiguration:devMenuConfiguration];
  return;
}

- (void)createReactHostIfNeeded:(NSDictionary *)launchOptions
           devMenuConfiguration:(RCTDevMenuConfiguration *)devMenuConfiguration
{
  if (self.reactHost) {
    return;
  }
  self.reactHost = [self createReactHost:launchOptions devMenuConfiguration:devMenuConfiguration];
}


- (RCTHost *)createReactHost:(NSDictionary *)launchOptions
        devMenuConfiguration:(RCTDevMenuConfiguration *)devMenuConfiguration
{
  __weak __typeof(self) weakSelf = self;
  RCTHost *reactHost =
      [[RCTHost alloc] initWithBundleURLProvider:self->_configuration.bundleURLBlock
                                    hostDelegate:_hostDelegate
                      turboModuleManagerDelegate:_turboModuleManagerDelegate
                                jsEngineProvider:^std::shared_ptr<facebook::react::JSRuntimeFactory>() {
                                  return [weakSelf createJSRuntimeFactory];
                                }
                                   launchOptions:launchOptions
                            devMenuConfiguration:devMenuConfiguration];
  // 设置 Bundle URL 提供者
  [reactHost setBundleURLProvider:^NSURL *() {
    return [weakSelf bundleURL];
  }];
  // 启动 ReactHost
  [reactHost start];
  return reactHost;
}
RCTInstance 初始化

继续跟踪RCTHoststart方法。源码react-native/packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTHost.mm

- (void)start
{
  // 1. 设置 Bundle URL
  if (_bundleURLProvider) {
    [self _setBundleURL:_bundleURLProvider()];
  }

  // 2. 设置 Inspector Target(用于调试)
  auto &inspectorFlags = jsinspector_modern::InspectorFlags::getInstance();
  if (inspectorFlags.getFuseboxEnabled() && !_inspectorPageId.has_value()) {
    _inspectorTarget =
        facebook::react::jsinspector_modern::HostTarget::create(*_inspectorHostDelegate, [](auto callback) {
          RCTExecuteOnMainQueue(^{
            callback();
          });
        });
    __weak RCTHost *weakSelf = self;
    _inspectorPageId = facebook::react::jsinspector_modern::getInspectorInstance().addPage(
        "React Native Bridgeless",
        /* vm */ "",
        [weakSelf](std::unique_ptr<facebook::react::jsinspector_modern::IRemoteConnection> remote)
            -> std::unique_ptr<facebook::react::jsinspector_modern::ILocalConnection> {
          RCTHost *strongSelf = weakSelf;
          if (!strongSelf) {
            // This can happen if we're about to be dealloc'd. Reject the connection.
            return nullptr;
          }
          return strongSelf->_inspectorTarget->connect(std::move(remote));
        },
        {.nativePageReloads = true, .prefersFuseboxFrontend = true});
  }
  if (_instance) {
    RCTLogWarn(
        @"RCTHost should not be creating a new instance if one already exists. This implies there is a bug with how/when this method is being called.");
    [_instance invalidate];
  }

  // 3. 创建 RCTInstance
  _instance = [[RCTInstance alloc] initWithDelegate:self
                                   jsRuntimeFactory:[self _provideJSEngine]
                                      bundleManager:_bundleManager
                         turboModuleManagerDelegate:_turboModuleManagerDelegate
                                     moduleRegistry:_moduleRegistry
                              parentInspectorTarget:_inspectorTarget.get()
                                      launchOptions:_launchOptions
                               devMenuConfiguration:_devMenuConfiguration];
  // 4. 通知代理 Host 已启动
  [_hostDelegate hostDidStart:self];
}

继续查看RCTInstance的构造实现,源码react-native/packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTInstance.mm

- (instancetype)initWithDelegate:(id<RCTInstanceDelegate>)delegate
                jsRuntimeFactory:(std::shared_ptr<facebook::react::JSRuntimeFactory>)jsRuntimeFactory
                   bundleManager:(RCTBundleManager *)bundleManager
      turboModuleManagerDelegate:(id<RCTTurboModuleManagerDelegate>)tmmDelegate
                  moduleRegistry:(RCTModuleRegistry *)moduleRegistry
           parentInspectorTarget:(jsinspector_modern::HostTarget *)parentInspectorTarget
                   launchOptions:(nullable NSDictionary *)launchOptions
            devMenuConfiguration:(RCTDevMenuConfiguration *)devMenuConfiguration
{
  if (self = [super init]) {
    // 性能监控初始化
    _performanceLogger = [RCTPerformanceLogger new];
    registerPerformanceLoggerHooks(_performanceLogger);
    [_performanceLogger markStartForTag:RCTPLReactInstanceInit];

    // 保存外部传入的关键依赖
    _delegate = delegate;
    _jsRuntimeFactory = jsRuntimeFactory;
    _appTMMDelegate = tmmDelegate;
    _jsThreadManager = [RCTJSThreadManager new];

    // 开发菜单配置
    _devMenuConfigurationDecorator =
#if RCT_DEV_MENU
        [[RCTDevMenuConfigurationDecorator alloc] initWithDevMenuConfiguration:devMenuConfiguration];
#else
        nil;
#endif

    _parentInspectorTarget = parentInspectorTarget;

    // JS 模块调用器配置(设置 Bridgeless 模式下的 JS 模块方法调用器)
    {
      __weak __typeof(self) weakSelf = self;
      [_bridgeModuleDecorator.callableJSModules
          setBridgelessJSModuleMethodInvoker:^(
              NSString *moduleName, NSString *methodName, NSArray *args, dispatch_block_t onComplete) {
            [weakSelf callFunctionOnJSModule:moduleName method:methodName args:args];
            if (onComplete) {
              [weakSelf
                  callFunctionOnBufferedRuntimeExecutor:[onComplete](facebook::jsi::Runtime &_) { onComplete(); }];
            }
          }];
    }
    _launchOptions = launchOptions;

    // 内存警告监听
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(_handleMemoryWarning)
                                                 name:UIApplicationDidReceiveMemoryWarningNotification
                                               object:nil];
    // 启动核心初始化
    [self _start];
  }
  return self;
}

接下来,我们来看整个初始化过程的核心方法_start实现:

- (void)_start
{
  // 1.设置定时器系统
  auto objCTimerRegistry = std::make_unique<ObjCTimerRegistry>();
  auto timing = objCTimerRegistry->timing;
  auto *objCTimerRegistryRawPtr = objCTimerRegistry.get();

  auto timerManager = std::make_shared<TimerManager>(std::move(objCTimerRegistry));
  objCTimerRegistryRawPtr->setTimerManager(timerManager);

  __weak __typeof(self) weakSelf = self;
  auto onJsError = [=](jsi::Runtime &runtime, const JsErrorHandler::ProcessedError &error) {
    [weakSelf _handleJSError:error withRuntime:runtime];
  };

  // 2.创建 ReactInstance (C++ 层)
  _reactInstance = std::make_unique<ReactInstance>(
      _jsRuntimeFactory->createJSRuntime(_jsThreadManager.jsMessageThread),
      _jsThreadManager.jsMessageThread,
      timerManager,
      onJsError,
      _parentInspectorTarget);
  _valid = true;

  // 3.设置 RuntimeExecutor
  RuntimeExecutor bufferedRuntimeExecutor = _reactInstance->getBufferedRuntimeExecutor();
  timerManager->setRuntimeExecutor(bufferedRuntimeExecutor);

  auto jsCallInvoker = make_shared<RuntimeSchedulerCallInvoker>(_reactInstance->getRuntimeScheduler());
  // 省略旧架构......

  // 4.创建 TurboModuleManager
  _turboModuleManager = [[RCTTurboModuleManager alloc] initWithBridgeProxy:bridgeProxy
                                                     bridgeModuleDecorator:_bridgeModuleDecorator
                                                                  delegate:self
                                                                 jsInvoker:jsCallInvoker
                                             devMenuConfigurationDecorator:_devMenuConfigurationDecorator];

#if RCT_DEV
  /**
    * 实例化 DevMenu 会产生副作用,即通过 RCTDevMenu 注册
    * CMD + d、CMD + i 和 CMD + n 的快捷键。 
    * 因此,启用 TurboModules 时,我们必须手动创建此NativeModule。
   */
  [_turboModuleManager moduleForName:"RCTDevMenu"];
#endif // end RCT_DEV

  // 初始化 RCTModuleRegistry,以便 TurboModules 可以引用其他 TurboModules
  [_bridgeModuleDecorator.moduleRegistry setTurboModuleRegistry:_turboModuleManager];

  if (ReactNativeFeatureFlags::enableEagerMainQueueModulesOnIOS()) {
    /**
     * 某些原生模块需要在主线程上捕获 UIKit 对象。
     * 因此,请在此处的主队列上开始初始化这些模块。JavaScript 线程将等待这些模块初始化完成后,才会执行 JavaScript 代码包。
     */
    NSArray<NSString *> *modulesRequiringMainQueueSetup = [_delegate unstableModulesRequiringMainQueueSetup];

    std::shared_ptr<std::mutex> mutex = std::make_shared<std::mutex>();
    std::shared_ptr<std::condition_variable> cv = std::make_shared<std::condition_variable>();
    std::shared_ptr<bool> isReady = std::make_shared<bool>(false);

    _waitUntilModuleSetupComplete = ^{
      std::unique_lock<std::mutex> lock(*mutex);
      cv->wait(lock, [isReady] { return *isReady; });
    };

    // TODO(T218039767): 将性能日志记录功能集成到主队列模块初始化过程中
    RCTExecuteOnMainQueue(^{
      for (NSString *moduleName in modulesRequiringMainQueueSetup) {
        [self->_bridgeModuleDecorator.moduleRegistry moduleForName:[moduleName UTF8String]];
      }

      RCTScreenSize();
      RCTScreenScale();
      RCTSwitchSize();

      std::lock_guard<std::mutex> lock(*mutex);
      *isReady = true;
      cv->notify_all();
    });
  }

  RCTLogSetBridgelessModuleRegistry(_bridgeModuleDecorator.moduleRegistry);
  RCTLogSetBridgelessCallableJSModules(_bridgeModuleDecorator.callableJSModules);

  // 5.创建 ContextContainer
  auto contextContainer = std::make_shared<ContextContainer>();
  [_delegate didCreateContextContainer:contextContainer];
  // 插入核心模块
  contextContainer->insert(
      "RCTImageLoader", facebook::react::wrapManagedObject([_turboModuleManager moduleForName:"RCTImageLoader"]));
  contextContainer->insert(
      "RCTEventDispatcher",
      facebook::react::wrapManagedObject([_turboModuleManager moduleForName:"RCTEventDispatcher"]));
  contextContainer->insert("RCTBridgeModuleDecorator", facebook::react::wrapManagedObject(_bridgeModuleDecorator));
  contextContainer->insert(RuntimeSchedulerKey, std::weak_ptr<RuntimeScheduler>(_reactInstance->getRuntimeScheduler()));
  contextContainer->insert("RCTBridgeProxy", facebook::react::wrapManagedObject(bridgeProxy));

  // 6.创建 SurfacePresenter
  _surfacePresenter = [[RCTSurfacePresenter alloc]
        initWithContextContainer:contextContainer
                 runtimeExecutor:bufferedRuntimeExecutor
      bridgelessBindingsExecutor:std::optional(_reactInstance->getUnbufferedRuntimeExecutor())];

  // 这使得模块中的 RCTViewRegistry 能够通过其 viewForReactTag 方法返回 UIView 对象
  __weak RCTSurfacePresenter *weakSurfacePresenter = _surfacePresenter;
  [_bridgeModuleDecorator.viewRegistry_DEPRECATED setBridgelessComponentViewProvider:^UIView *(NSNumber *reactTag) {
    RCTSurfacePresenter *strongSurfacePresenter = weakSurfacePresenter;
    if (strongSurfacePresenter == nil) {
      return nil;
    }

    return [strongSurfacePresenter findComponentViewWithTag_DO_NOT_USE_DEPRECATED:reactTag.integerValue];
  }];

  // 7.创建DisplayLink (用于调用计时器回调函数)
  _displayLink = [RCTDisplayLink new];

  auto &inspectorFlags = jsinspector_modern::InspectorFlags::getInstance();

  ReactInstance::JSRuntimeFlags options = {
      .isProfiling = inspectorFlags.getIsProfilingBuild(),
      .runtimeDiagnosticFlags = [RCTInstanceRuntimeDiagnosticFlags() UTF8String]};

  // 8.初始化 JS Runtime 并加载 Bundle
  _reactInstance->initializeRuntime(options, [=](jsi::Runtime &runtime) {
    __strong __typeof(self) strongSelf = weakSelf;
    if (!strongSelf) {
      return;
    }

    // 安装 TurboModule JS 绑定
    [strongSelf->_turboModuleManager installJSBindings:runtime];
    // 绑定 Native Logger
    facebook::react::bindNativeLogger(runtime, [](const std::string &message, unsigned int logLevel) {
      _RCTLogJavaScriptInternal(static_cast<RCTLogLevel>(logLevel), [NSString stringWithUTF8String:message.c_str()]);
    });

    // 安装 Native Component Registry 绑定
    RCTInstallNativeComponentRegistryBinding(runtime);

    // 通知代理 Runtime 已初始化
    [strongSelf->_delegate instance:strongSelf didInitializeRuntime:runtime];

    // 设置 DisplayLink
    id<RCTDisplayLinkModuleHolder> moduleHolder = [[RCTBridgelessDisplayLinkModuleHolder alloc] initWithModule:timing];
    [strongSelf->_displayLink registerModuleForFrameUpdates:timing withModuleHolder:moduleHolder];
    [strongSelf->_displayLink addToRunLoop:[NSRunLoop currentRunLoop]];

    // 尝试同步加载bundle包,如果失败则回退到异步加载。
    [strongSelf->_performanceLogger markStartForTag:RCTPLScriptDownload];
    [strongSelf _loadJSBundle:[strongSelf->_bridgeModuleDecorator.bundleManager bundleURL]];
  });

  [_performanceLogger markStopForTag:RCTPLReactInstanceInit];
}
JS Bundle 加载

继续查看_loadJSBundle方法的实现:

- (void)_loadJSBundle:(NSURL *)sourceURL
{
#if RCT_DEV_MENU && __has_include(<React/RCTDevLoadingViewProtocol.h>)
  {
    // 显示加载视图
    id<RCTDevLoadingViewProtocol> loadingView =
        (id<RCTDevLoadingViewProtocol>)[_turboModuleManager moduleForName:"DevLoadingView"];
    [loadingView showWithURL:sourceURL];
  }
#endif

  __weak __typeof(self) weakSelf = self;
  // 通过代理加载 Bundle
  [_delegate loadBundleAtURL:sourceURL
      onProgress:^(RCTLoadingProgress *progressData) {
        __typeof(self) strongSelf = weakSelf;
        if (!strongSelf) {
          return;
        }

#if RCT_DEV_MENU && __has_include(<React/RCTDevLoadingViewProtocol.h>)
        id<RCTDevLoadingViewProtocol> loadingView =
            (id<RCTDevLoadingViewProtocol>)[strongSelf->_turboModuleManager moduleForName:"DevLoadingView"];
        [loadingView updateProgress:progressData];
#endif
      }
      onComplete:^(NSError *error, RCTSource *source) {
        __typeof(self) strongSelf = weakSelf;
        if (!strongSelf) {
          return;
        }

        if (error) {
          [strongSelf handleBundleLoadingError:error];
          return;
        }
        // _loadScriptFromSource 函数的回调函数需要 DevSettings 模块,因此需要提前进行初始化。
        RCTDevSettings *const devSettings =
            (RCTDevSettings *)[strongSelf->_turboModuleManager moduleForName:"DevSettings"];

        // 加载脚本
        [strongSelf _loadScriptFromSource:source];
        // 仅在开发环境中启用热模块重载功能。
        [strongSelf->_performanceLogger markStopForTag:RCTPLScriptDownload];
        [devSettings setupHMRClientWithBundleURL:sourceURL];
#if RCT_DEV
        [strongSelf _logOldArchitectureWarnings];
#endif
      }];
}


- (void)_loadScriptFromSource:(RCTSource *)source
{
  std::lock_guard<std::mutex> lock(_invalidationMutex);
  if (!_valid) {
    return;
  }

  auto script = std::make_unique<NSDataBigString>(source.data);
  const auto *url = deriveSourceURL(source.url).UTF8String;

  auto beforeLoad = [waitUntilModuleSetupComplete = self->_waitUntilModuleSetupComplete](jsi::Runtime &_) {
    if (waitUntilModuleSetupComplete) {
      waitUntilModuleSetupComplete();
    }
  };
  auto afterLoad = [](jsi::Runtime &_) {
    [[NSNotificationCenter defaultCenter] postNotificationName:@"RCTInstanceDidLoadBundle" object:nil];
  };
  // 在 ReactInstance 中执行脚本
  _reactInstance->loadScript(std::move(script), url, beforeLoad, afterLoad);
}
Surface 创建与启动

现在,我们把视线拉回viewWithModuleName方法中,继续分析后面的createSurfaceWithModuleName方法的实现。源码RCTHost.mm

- (RCTFabricSurface *)createSurfaceWithModuleName:(NSString *)moduleName initialProperties:(NSDictionary *)properties
{
  return [self createSurfaceWithModuleName:moduleName mode:DisplayMode::Visible initialProperties:properties];
}

- (RCTFabricSurface *)createSurfaceWithModuleName:(NSString *)moduleName
                                             mode:(DisplayMode)displayMode
                                initialProperties:(NSDictionary *)properties
{
  // 1. 创建 FabricSurface
  RCTFabricSurface *surface = [[RCTFabricSurface alloc] initWithSurfacePresenter:self.surfacePresenter
                                                                      moduleName:moduleName
                                                               initialProperties:properties];
  // 2. 设置显示模式
  surface.surfaceHandler.setDisplayMode(displayMode);

  // 3. 附加 Surface
  [self _attachSurface:surface];

  __weak RCTFabricSurface *weakSurface = surface;
  // 在 JS Bundle 执行完成后,使用BufferedRuntimeExecutor启动Surface
  [_instance callFunctionOnBufferedRuntimeExecutor:[weakSurface](facebook::jsi::Runtime &_) { [weakSurface start]; }];
  return surface;
}

总结

初始化的大概流程:

┌─────────────────────────────────────────────────────────────────┐
                        Swift 应用层                              
  ┌─────────────────────────────────────────────────────────────┐│
    AppDelegate                                                 ││
      ├── reactNativeDelegate: ReactNativeDelegate             ││
      └── reactNativeFactory: RCTReactNativeFactory             ││
  └─────────────────────────────────────────────────────────────┘│
  ┌─────────────────────────────────────────────────────────────┐│
    ReactNativeDelegate : RCTDefaultReactNativeFactoryDelegate  ││
      ├── bundleURL()  URL?                                    ││
      └── dependencyProvider: RCTAppDependencyProvider          ││
  └─────────────────────────────────────────────────────────────┘│
└─────────────────────────────────────────────────────────────────┘
                               
                               
┌─────────────────────────────────────────────────────────────────┐
                        Factory                                 
  ┌─────────────────────────────────────────────────────────────┐│
    RCTReactNativeFactory                                       ││
      ├── delegate: RCTReactNativeFactoryDelegate               ││
      ├── rootViewFactory: RCTRootViewFactory                   ││
      └── startReactNative(withModuleName:in:)                  ││
  └─────────────────────────────────────────────────────────────┘│
  ┌─────────────────────────────────────────────────────────────┐│
    RCTRootViewFactory                                          ││
      ├── reactHost: RCTHost                                    ││
      ├── view(withModuleName:)  UIView                        ││
      └── createReactHost()  RCTHost                           ││
  └─────────────────────────────────────────────────────────────┘│
└─────────────────────────────────────────────────────────────────┘
                               
                               
┌─────────────────────────────────────────────────────────────────┐
                         Host                                   
  ┌─────────────────────────────────────────────────────────────┐│
    RCTHost                                                     ││
      ├── instance: RCTInstance                                 ││
      ├── bundleManager: RCTBundleManager                       ││
      ├── start()                                               ││
      └── createSurface(withModuleName:)  RCTFabricSurface     ││
  └─────────────────────────────────────────────────────────────┘│
└─────────────────────────────────────────────────────────────────┘
                               
                               
┌─────────────────────────────────────────────────────────────────┐
                       Instance                                 
  ┌─────────────────────────────────────────────────────────────┐│
    RCTInstance                                                 ││
      ├── reactInstance: ReactInstance (C++)                    ││
      ├── turboModuleManager: RCTTurboModuleManager             ││
      ├── surfacePresenter: RCTSurfacePresenter                 ││
      ├── displayLink: RCTDisplayLink                           ││
      └── _start()                                              ││
  └─────────────────────────────────────────────────────────────┘│
└─────────────────────────────────────────────────────────────────┘
                               
                               
┌─────────────────────────────────────────────────────────────────┐
                        C++ Runtime                             
  ┌─────────────────────────────────────────────────────────────┐│
    ReactInstance (C++)                                         ││
      ├── jsRuntime: jsi::Runtime (Hermes)                      ││
      ├── runtimeScheduler: RuntimeScheduler                    ││
      ├── timerManager: TimerManager                            ││
      ├── initializeRuntime()                                   ││
      └── loadScript()                                          ││
  └─────────────────────────────────────────────────────────────┘│
└─────────────────────────────────────────────────────────────────┘

90% 的人读不懂 Vue 源码,是因为没做这些准备

作者 墨色
2026年1月28日 17:40

前言

相信很多人阅读源码都是从响应式开始看起的,clone vue源码之后,查看reactivity下的reactive.ts模块,一行行阅读;十分钟后,合上编辑器,心里只剩下一个问题:“是我太菜,还是源码本来就看不懂?”

事实是——绝大多数人不是看不懂源码,而是用错了方式。

源码不是文档,它不是按“教学顺序”写的,而是按工程、性能和长期维护来组织的。如果你在不了解项目结构、不知道入口、不具备调试手段的情况下直接硬读,很容易陷入“每一行都认识,但整体完全不懂”的状态。

这也是为什么:
90% 的人读不懂 Vue 源码,并不是能力问题,而是没做阅读前的准备。

为什么要读源码

在阅读源码前,我们一定要问自己:为什么阅读源码? 自己希望从源码中得知什么?

如今源码阅读已成潮流,其中不乏培训机构的过度鼓吹,制造 “不懂源码就找不到工作” 的焦虑,让很多人盲目卷入内卷。但回归现实,多数面试并不会深究源码细节,核心还是考察 Vue 的设计思想与核心原理。如果单纯为了应试,针对性梳理高频面试题、核心知识点,远比通读源码简单高效、性价比更高。

而如果是出于对技术的兴趣,想要揭开 Vue 内部的运行原理,学习框架中精妙的设计思路、架构模式与工程化实践,或是为了解决开发中难以定位的疑难问题、完成框架的二次封装与定制开发,深入研读源码就非常有必要。这能帮我们跳出 “只会使用框架” 的层面,真正理解底层逻辑,大幅提升架构思维与问题解决能力。

源码不是让你“一行行啃”,而是让你“顺着主线走”

很多人一提到“读源码”,脑海里就会自动等同成:
从第一行看到最后一行,一行都不能漏。

但这恰恰是读源码最容易走偏的地方。

以 Vue 为例,源码中充满了大量的:

  • 边界判断(if (__DEV__)if (!isObject)
  • 兼容处理
  • 性能优化分支
  • 为极端场景准备的兜底逻辑

这些代码本身没有错,但如果一开始就死磕每一个分支,只会让你迅速迷失在细节里。

  • 真正高效的源码阅读方式:抓住「核心主线」

读源码时,更重要的不是“这一行在干嘛”,
而是先回答清楚这三个问题:

  1. 这个模块的核心职责是什么?
  2. 主流程是如何从入口一路走到出口的?
  3. 中途哪些是核心逻辑,哪些是边界保护?

比如在 Vue 响应式系统中:

  • 主线只有一条

    访问数据 → 依赖收集 → 数据变化 → 触发更新

只要你能顺着这条主线走通:

  • track 什么时候执行
  • trigger 如何通知订阅者
  • effect / computed 是如何被调度的

那些零散的判断条件,其实都是围绕主线展开的“护栏”。

  • 边界判断不是现在的重点

这并不意味着边界判断不重要,而是:

它们更适合在你第二次、第三次读源码时再深入。

第一次读源码,你的目标应该是:

  • 建立整体执行流程的心智模型
  • 知道“这一坨代码大概负责什么”
  • 能把关键函数串成一条完整链路

当你已经清楚主线之后,再回头看这些判断:

  • 你会知道为什么要加

  • 也能理解为什么要写得这么绕

  • 甚至能体会到框架作者在做取舍时的无奈

  • 用调试而不是“意念”来跟主线

抓主线还有一个非常重要的前提:
不要靠猜,而是让代码跑起来。

通过 SourceMap + 断点:

  • 从入口函数开始打断点
  • 顺着调用栈一路向下
  • 只跟踪你当前关心的那条路径

你会发现:

  • 80% 的代码你暂时根本不用看
  • 真正影响理解的,往往只有那 20% 的核心逻辑

开启sourceMap

接下来让我们揭开Vue的神秘面纱 Vue3源码地址, 推荐大家fork项目到自己仓库阅读

Vue 的源码并不是一堆散乱的文件,而是一个 Monorepo 工程,核心逻辑被清晰地拆分在 packages 目录,我们在vue源码的文档中,可以看到详细的介绍github.com/vuejs/core/…

image.png

运行pnpm install安装相关依赖

vue源码项目采用的是rollup进行打包的,我们可以查看package.json打包命令, "build": "build": "node scripts/build.js", 运行pnpm build生成 dist 打包文件

我们在packages/vue/examples下创建自己的demo文件夹,比如说之后我想看响应式相关源码,可以创建类似的demo文件 packages/vue/examples/demo/reactive/index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Vue Effect Test</title>

    <!-- 引入你本地 clone 的 vue.global.js -->
    <script src="../../../../vue/dist/vue.global.js"></script>
</head>

<body>
    <div id="text"></div>
    <div id="text1"></div>
    <button id="btn">count1++</button>
    <button id="btn2">count2++</button> 

    <script>
        const { reactive, ref, effect } = Vue;

        // 创建响应式数据
        const state = reactive({
            count1: 1,
            count2: 10
        });

        // 绑定 effect:依赖收集 + 自动更新
        effect(() => {
            document.getElementById('text').innerText =
                `当前 count 值:${state.count1 + state.count2}`;
        });

        effect(() => {
            document.getElementById('text1').innerText =
                `当前 count 值:${state.count1 + state.count2 + 100}`;
        });


        // 事件:修改数据触发 effect 自动执行
        document.getElementById('btn').onclick = () => {
            state.count1++;
            state.count2++;
        };
        document.getElementById('btn2').onclick = () => {
            state.count1 = state.count1 + 5;
            state.count2 = state.count2 + 5
        };
    </script>
</body>
</html>

然后通过liveServer打开index.html(需要安装live server插件) image.png 但是我们会发现在source中查看源代码,发现并没有开启 sourceMap

image.png

接下来我们开始vuesourceMap, 我们可以看到pnpm build命令质上还是执行的script文件夹下的build.js打包脚本

image.png 而这个sourceMap开始是在指令中通过-s开启的

image.png

rollup.config.js会根据sourceMap指令生成sourceMap文件

image.png

接下来我们修改在package.json中的build脚本,增加-s标识("build": "node scripts/build.js -s",), 然后重新执行 pnpm build, 这样打包出来的文件就有sourceMap文件

image.png

源码debuger技巧

比如说,我们想看响应式相关的逻辑,可以找到reactive函数处,设置断点,然后按步骤阅读 image.png

总结

本节主要介绍阅读源码前的准备,后续将逐步带大家阅读vue源码, 如果对你有帮助,帮忙点个关注、赞~

昨天以前首页

🔥🔥🔥 React18 源码学习 - DIFF算法

作者 yyyao
2026年1月26日 09:43

前言

本文的React代码版本为18.2.0

可调试的代码仓库为:GitHub - yyyao-hh/react-debug at master-pure

React的世界里,每次状态更新都会触发组件的重新渲染。如果直接销毁旧DOM节点并创建新节点,性能开销将无法承受。React通过调和(Reconciliation) 过程,配合DIFF算法,找出需要更新的最小节点集合,实现了高效的UI更新。

本文将带你深React18源码,揭示DIFF算法的核心原理、实现细节和优化策略。

DIFF 算法的策略

策略一:同级比较

React只会对同一层级的节点进行比较,不会跨层级追踪节点变化。

策略二:类型不同则销毁重建

如果节点类型改变,React会直接销毁整个子树,重新构建新的节点。

策略三:Key 值优化列表更新

React使用key来匹配原有树上的子元素,匹配成功就会进行复用。通过key标识节点的稳定性,React可以更准确地识别节点的移动、添加和删除,使得树的转换效率得以提高。

比如:两个同级兄弟节点位置进行了调换,存在key的情况下两个节点都会被复用,而不是卸载重新构建。

DIFF 算法的入口

在上一节我们讲构建Fiber树的时候,讲到了beginWork方法内部主要是根据tag分发逻辑,处理不同类型的Fiber节点。将处理方法的返回的子节点作为下一个遍历节点

/* packages/react-reconciler/src/ReactFiberBeginWork.old.js */

function beginWork(
  current: Fiber | null,
  workInProgress: Fiber,
  renderLanes: Lanes,
): Fiber | null {
  if(...) {...}; // 满足一定条件下执行熔断策略

  switch (workInProgress.tag) {
    case IndeterminateComponent: return mountIndeterminateComponent(...);
    case LazyComponent: return mountLazyComponent(...);
    case FunctionComponent: return updateFunctionComponent(...);
    case ClassComponent: return updateClassComponent(...);
    case HostRoot: return updateHostRoot(...);
    case HostComponent: return updateHostComponent(...);
    case HostText: return updateHostText(...);
    case SuspenseComponent: return updateSuspenseComponent(...);
    case HostPortal: return updatePortalComponent(...);
    case ForwardRef: return updateForwardRef(...);
    case Fragment: return updateFragment(...);
    case Mode: return updateMode(...);
    case Profiler: return updateProfiler(...);
    case ContextProvider: return updateContextProvider(...);
    case ContextConsumer: return updateContextConsumer(...);
    case MemoComponent: return updateMemoComponent(...);
    case SimpleMemoComponent: return updateSimpleMemoComponent(...);
    case IncompleteClassComponent: return mountIncompleteClassComponent(...);
    case SuspenseListComponent: return updateSuspenseListComponent(...);
    case ScopeComponent: return updateScopeComponent(...);
    case OffscreenComponent: return updateOffscreenComponent(...);
    case LegacyHiddenComponent: return updateLegacyHiddenComponent(...);
    case CacheComponent: return updateCacheComponent(...);
    case TracingMarkerComponent: return updateTracingMarkerComponent(...);
  }
}

这些不同的处理逻辑最终都会走到reconcileChildren函数中去处理,这里简单以类组件(ClassComponent)和函数式组件(FunctionComponent)的举例:

// 类组件 (ClassComponent)
function updateClassComponent(...) {
  const nextUnitOfWork = finishClassComponent(...);
  
  return nextUnitOfWork;
}

function finishClassComponent(...) {
  reconcileChildren(current, workInProgress, nextChildren, renderLanes);

  return workInProgress.child;
}

// 函数式组件 (FunctionComponent)
function updateFunctionComponent(...) {
  reconcileChildren(current, workInProgress, nextChildren, renderLanes);
  
  return workInProgress.child;
}
/* src/react/packages/react-reconciler/src/ReactFiberBeginWork.old.js */

export function reconcileChildren(...) {
  if (current === null) {
    workInProgress.child = mountChildFibers(...);
  } else {
    workInProgress.child = reconcileChildFibers(...);
  }
}
/* src/react/packages/react-reconciler/src/ReactChildFiber.old.js */

export const reconcileChildFibers = ChildReconciler(true);
export const mountChildFibers = ChildReconciler(false);
/* src/react/packages/react-reconciler/src/ReactChildFiber.old.js */

function ChildReconciler(shouldTrackSideEffects) {

  ...

  function reconcileChildFibers() {}

  return reconcileChildFibers;
}

所以reconcileChildFibers函数是实现Diff算法的核心方法

DIFF 算法的实现

我们紧接着入口之后,来分析reconcileChildFibers函数的内部逻辑。

  1. 首先处理顶级且无keyFragment元素,满足条件则直接使用它的孩子。这里值得注意的两点:

    a. 存在keyFragment不满足条件,于是乎在下方“处理单元素”逻辑中又会处理一下。

    b. 非顶级的Fragment依旧不满足条件,在下方“处理数组元素”的逻辑中会进行处理。

  2. 如果是一个对象,那么它是一个ReactElement。分为普通元素、Lazy组件、Portal组件、节点数组、可迭代对象分别进行处理;

  3. 如果是stringnumber类型,调用处理文本节点的方法。

  4. 剩余情况:可能为nullundefinedfalse'',不能转化为Fiber节点,因此直接删除所有旧子Fiber节点。

function reconcileChildFibers(
  returnFiber: Fiber,
  currentFirstChild: Fiber | null,
  newChild: any,
  lanes: Lanes,
): Fiber | null {
  
  /* 1. 顶级无key的Fragment元素, 直接使用它的children */
  const isUnkeyedTopLevelFragment =
    typeof newChild === 'object' &&
    newChild !== null &&
    newChild.type === REACT_FRAGMENT_TYPE &&
    newChild.key === null;
  if (isUnkeyedTopLevelFragment) {
    newChild = newChild.props.children;
  }

  /* 2. 处理对象类型 */
  if (typeof newChild === 'object' && newChild !== null) {
    switch (newChild.$$typeof) {
      // 2.1 React 元素
      case REACT_ELEMENT_TYPE:
        return placeSingleChild(
          reconcileSingleElement(
            returnFiber,
            currentFirstChild,
            newChild,
            lanes,
          ),
        );
      // 2.2 Portal
      case REACT_PORTAL_TYPE:
        return placeSingleChild(
          reconcileSinglePortal(
            returnFiber,
            currentFirstChild,
            newChild,
            lanes,
          ),
        );
      // 2.3 懒加载组件
      case REACT_LAZY_TYPE:
        const payload = newChild._payload;
        const init = newChild._init;
        return reconcileChildFibers(
          returnFiber,
          currentFirstChild,
          init(payload),
          lanes,
        );
    }

    // 2.4. 数组类型处理
    if (isArray(newChild)) {
      return reconcileChildrenArray(
        returnFiber,
        currentFirstChild,
        newChild,
        lanes,
      );
    }

    // 2.5 可迭代对象处理
    if (getIteratorFn(newChild)) {
      return reconcileChildrenIterator(
        returnFiber,
        currentFirstChild,
        newChild,
        lanes,
      );
    }

    // 2.6 无效对象类型错误
    throwOnInvalidObjectType(returnFiber, newChild);
  }

  /* 3. 处理文本节点类型 */
  if (
    (typeof newChild === 'string' && newChild !== '') ||
    typeof newChild === 'number'
  ) {
    return placeSingleChild(
      reconcileSingleTextNode(
        returnFiber,
        currentFirstChild,
        '' + newChild,
        lanes,
      ),
    );
  }

  /* 4. 剩余情况 */
  return deleteRemainingChildren(returnFiber, currentFirstChild);
}

处理单节点

reconcileSingleElement方法用于处理当新的子节点是一个单独的元素(不是数组或文本节点)时的情况。

它的处理分为两个阶段,判断条件便是child !== null

  1. 更新阶段(while循环)
  2. 初始化阶段或在循环中不满足复用条件(while循环之后)

首先while循环的逻辑:遍历旧子Fiber节点,尝试找到可以复用的Fiber节点:

  • 如果key相同且type相同,则复用并删除其他兄弟节点;
  • 如果key相同但type不同,则删除包括当前节点在内的所有子节点,然后跳出循环;
  • 如果key不同,则标记当前child为删除,继续遍历下一个兄弟节点。

然后是循环之后的逻辑:遍历完或break后未找到可复用节点,直接创建新的Fiber节点。

function reconcileSingleElement(
  returnFiber: Fiber,
  currentFirstChild: Fiber | null,
  element: ReactElement,
  lanes: Lanes,
): Fiber {
  const key = element.key;
  let child = currentFirstChild;
  /**
   * 1. 更新阶段
   * - 如果key相同且type相同, 则复用并删除其他兄弟节点
   * - 如果key相同但type不同, 则删除包括当前节点在内的所有子节点, 然后跳出循环
   * - 如果key不同, 则标记当前child为删除, 继续遍历下一个兄弟节点
   */
  while (child !== null) {
    if (child.key === key) {
      const elementType = element.type;
      if (elementType === REACT_FRAGMENT_TYPE) {
        if (child.tag === Fragment) {
          deleteRemainingChildren(returnFiber, child.sibling);
          const existing = useFiber(child, element.props.children);
          existing.return = returnFiber;
          return existing;
        }
      } else {
        if (
          child.elementType === elementType ||
          (__DEV__
            ? isCompatibleFamilyForHotReloading(child, element)
            : false) ||
          (typeof elementType === 'object' &&
            elementType !== null &&
            elementType.$$typeof === REACT_LAZY_TYPE &&
            resolveLazy(elementType) === child.type)
        ) {
          deleteRemainingChildren(returnFiber, child.sibling);
          const existing = useFiber(child, element.props);
          existing.ref = coerceRef(returnFiber, child, element);
          existing.return = returnFiber;
          return existing;
        }
      }
      // key相同, 类型不同, 删除该节点和其兄弟节点
      deleteRemainingChildren(returnFiber, child);
      break;
    } else {
      // 如果key不同, 则标记当前child为删除, 继续遍历下一个兄弟节点
      deleteChild(returnFiber, child);
    }
    child = child.sibling;
  }

  /**
   * 2. 初始化阶段 | 或循环中不满足复用条件, 直接创建新的Fiber节点
   */
  if (element.type === REACT_FRAGMENT_TYPE) { // Fragment 组件
    const created = createFiberFromFragment(
      element.props.children,
      returnFiber.mode,
      lanes,
      element.key,
    );
    created.return = returnFiber;
    return created;
  } else { // 原生DOM元素、函数组件、类组件等
    const created = createFiberFromElement(element, returnFiber.mode, lanes);
    created.ref = coerceRef(returnFiber, currentFirstChild, element);
    created.return = returnFiber;
    return created;
  }
}

总结下reconcileSingleElement方法的作用:负责处理单个React元素的更新,它的目标:

  1. 在现有子节点链表中找到可以复用的节点
  2. 删除不需要的旧节点(打标记,commit阶段处理)
  3. 创建新的Fiber节点(如果没有可复用的)

处理多节点

reconcileChildrenArray函数负责协调一个数组类型的子元素列表。

  1. 第一次循环:同时遍历旧的子Fiber节点链表和新的子元素数组,直到其中一个遍历完。
    在遍历中,通过updateSlot函数尝试复用旧节点(key相同则复用,否则返回null)。
    1. 如果复用失败(key不同),则跳出循环。
    2. 如果复用成功,但是位置可能发生变化,则通过placeChild标记位置(是否需要移动)。
  1. 如果新子元素数组遍历完(newIdx === newChildren.length),说明剩下的旧节点都是多余,需要删除。
  2. 如果旧节点链表遍历完(oldFiber === null),说明剩下的新子元素都是需要新增的,直接循环创建新的Fiber节点。
  3. 如果以上都不是,说明有节点位置发生变化(比如中间插入了新节点,或者节点被删除导致旧节点有剩余),此时将剩余的旧节点放入一个Map中(key作为索引,如果没有key则用index),然后继续遍历新子元素数组,从Map中查找可复用的节点,并标记移动。
  4. 最后,如果还有旧节点未被复用,则标记删除。
function reconcileChildrenArray(
  returnFiber: Fiber,
  currentFirstChild: Fiber | null,
  newChildren: Array<*>,
  lanes: Lanes,
): Fiber | null {
  let resultingFirstChild: Fiber | null = null; // 结果链表的头节点
  let previousNewFiber: Fiber | null = null;    // 上一个创建的Fiber

  let oldFiber = currentFirstChild; // 旧Fiber链表的节点, 开始指向同层的第一个节点
  let lastPlacedIndex = 0;          // 已经处理完的节点中,最后一个"不需要移动"的节点在旧列表中的位置
  let newIdx = 0;                   // 新children数组的当前索引
  let nextOldFiber = null;          // 下一个要处理的旧Fiber(临时存储)
  /**
   * 1. 同时遍历旧的子Fiber节点链表和新的子元素数组, 直到其中一个遍历完
   */
  for (; oldFiber !== null && newIdx < newChildren.length; newIdx++) {
    if (oldFiber.index > newIdx) {
      nextOldFiber = oldFiber;
      oldFiber = null;
    } else {
      nextOldFiber = oldFiber.sibling;
    }
    // updateSlot: 尝试复用旧节点(key相同则复用,否则返回null)
    const newFiber = updateSlot(
      returnFiber,
      oldFiber,
      newChildren[newIdx],
      lanes,
    );
    // 匹配失败, 不能复用
    if (newFiber === null) {
      if (oldFiber === null) {
        oldFiber = nextOldFiber;
      }
      break;
    }
    if (shouldTrackSideEffects) {
      if (oldFiber && newFiber.alternate === null) {
        deleteChild(returnFiber, oldFiber);
      }
    }
    lastPlacedIndex = placeChild(newFiber, lastPlacedIndex, newIdx);
    // 
    if (previousNewFiber === null) {
      resultingFirstChild = newFiber;
    } else {
      previousNewFiber.sibling = newFiber;
    }
    previousNewFiber = newFiber;
    oldFiber = nextOldFiber;
  }

  /**
   * 2. 如果新子元素数组遍历完, 说明剩下的旧节点都是多余, 需要删除
   */
  if (newIdx === newChildren.length) {
    deleteRemainingChildren(returnFiber, oldFiber);
    return resultingFirstChild;
  }

  /**
   * 3. 如果旧节点链表遍历完, 说明剩下的新子元素都是需要新增的, 直接循环创建
   */
  if (oldFiber === null) {
    for (; newIdx < newChildren.length; newIdx++) {
      const newFiber = createChild(returnFiber, newChildren[newIdx], lanes);
      if (newFiber === null) {
        continue;
      }
      lastPlacedIndex = placeChild(newFiber, lastPlacedIndex, newIdx);
      if (previousNewFiber === null) {
        resultingFirstChild = newFiber;
      } else {
        previousNewFiber.sibling = newFiber;
      }
      previousNewFiber = newFiber;
    }
    return resultingFirstChild;
  }

  /**
   * 4. 如果以上都不是, 说明有节点位置发生变化, 此时将剩余的旧节点放入一个Map中,
   * 然后继续遍历新子元素数组, 从Map中查找可复用的节点, 并标记移动
   */
  const existingChildren = mapRemainingChildren(returnFiber, oldFiber);
  for (; newIdx < newChildren.length; newIdx++) {
    const newFiber = updateFromMap(
      existingChildren,
      returnFiber,
      newIdx,
      newChildren[newIdx],
      lanes,
    );
    if (newFiber !== null) {
      if (shouldTrackSideEffects) {
        if (newFiber.alternate !== null) {
          existingChildren.delete(
            newFiber.key === null ? newIdx : newFiber.key,
          );
        }
      }
      lastPlacedIndex = placeChild(newFiber, lastPlacedIndex, newIdx);
      if (previousNewFiber === null) {
        resultingFirstChild = newFiber;
      } else {
        previousNewFiber.sibling = newFiber;
      }
      previousNewFiber = newFiber;
    }
  }

  /**
   * 5. 最后, 如果还有旧节点未被复用, 则标记删除
   */
  if (shouldTrackSideEffects) {
    existingChildren.forEach(child => deleteChild(returnFiber, child));
  }

  return resultingFirstChild;
}

总结下reconcileChildrenArray方法的作用:负责协调一个数组类型的子元素列表,它的设计:

第一阶段:顺序比较(处理相同位置节点)

第二阶段:处理新增/删除边界

第三阶段:Map查找(处理节点移动)

实际案例:列表重排的DIFF过程

假设有如下列表更新:

// 更新前
<ul>
  <li key="A">A</li>
  <li key="B">B</li>
  <li key="C">C</li>
  <li key="D">D</li>
</ul>

// 更新后(D移动到B之前)
<ul>
  <li key="A">A</li>
  <li key="D">D</li>
  <li key="B">B</li>
  <li key="C">C</li>
</ul>

DIFF过程:

  1. 第一轮遍历:比较A-A(复用),比较B-Dkey不同,跳出第一轮)
  2. 建立Map:{B: B_Fiber, C: C_Fiber, D: D_Fiber}
  3. 第二轮遍历:
    • 处理D:从Map中找到D_FiberlastPlacedIndex=0oldIndex=3>0,不需要移动
    • 处理B:从Map中找到B_FiberlastPlacedIndex=3oldIndex=1<3,需要移动
    • 处理C:从Map中找到C_FiberlastPlacedIndex=3oldIndex=2<3,需要移动
  1. 结果:D保持原位,BC向后移动

总结

ReactDIFF算法是一个经过精心设计和不断优化的复杂系统。从React16Fiber架构到React18的并发特性,DIFF算法始终围绕着以下核心目标:

  1. 高效性:通过O(n)复杂度的算法快速找出差异
  2. 稳定性:确保在可中断渲染中UI的一致性
  3. 可预测性:开发者可以通过key等手段控制更新行为
  4. 渐进增强:支持并发渲染,提高应用响应速度

下一章我们将了解真实DOM的变更:commit阶段

❌
❌