React Native新架构源码分析

一、背景

需要了解RN的新架构原理,看看它主要增加了什么,解决了什么问题,主要文章为:reactnative.dev/architectur...

备注:涉及到大量源码分析想要看完耗时较久,可以先点赞和收藏再看^_^,文章里的图片,流程图,代码看着不清晰可以直接访问我的语雀文档React Native新架构原理分析

1.1 旧架构的问题

从以上图我们就可以看出来它的问题:

  • js和native的通信都是通过桥来做的,如果频繁通信大量的序列化操作会影响其性能和内存占用;在通过消息队列机制来处理会让js和native的操作都是异步化的
  • 旧架构的渲染,shadow树是分不同端实现的,例如Android,主要的逻辑在Java侧,这样渲染逻辑不仅多了一层JNI调用,而且还导致双端不统一,要分端维护。

1.2 新架构的解决方法

我们再来看看新架构是如何做的呢:

  • 原来的操作是通过桥通信,大量不必要的序列化,那就移除序列化,直接使用JSI,让JS有可以直接操作C++的能力
  • 原来是异步操作,直接通过JSI改成同步操作
  • 原来渲染Shadow树是在双端各自维护的渲染逻辑,改到C++层,统一渲染层Fabric
  • 桥通信和定义要大量的心智负担,例如类型怕定义错误,它是否为null等,直接引入codegen,只需要定义一次接口,自动生成多端代码

二、新架构介绍

自 2018 年以来,React Native 团队一直在重新设计其核心内部结构,以帮助开发者创造更高质量的体验。截至 2024 年,此版本的 React Native 已得到大规模验证,并由 Meta 提供支持生产环境的应用。

新架构自 React Native 0.68 版本起已开放实验性选择,并在后续每个版本中持续改进。团队目前正致力于使其成为 React Native 开源生态系统的默认体验。

新架构的渲染基准测试:

github.com/reactwg/rea...

三、新旧架构对比

我们用同一个FlatList渲染列表,分别跑在旧架构和新架构中看下性能如何

cpp 复制代码
import React, { useState, useCallback, useRef, useEffect } from 'react';
import {
  SafeAreaView,
  StyleSheet,
  Text,
  View,
  FlatList,
  Image,
  ActivityIndicator,
  Platform,
  Dimensions,
  Animated,
  Easing,
  UIManager,
  findNodeHandle,
  ScrollView,
  NativeModules,
} from 'react-native';

// 强制启用LayoutAnimation(Android需要)
if (Platform.OS === 'android') {
  if (UIManager.setLayoutAnimationEnabledExperimental) {
    UIManager.setLayoutAnimationEnabledExperimental(true);
  }
}

// 判断当前是否使用新架构的更可靠方法
const checkArchitecture = () => {
  const isNewArch = 
    // 检查TurboModule是否存在
    global.__turboModuleProxy !== undefined || 
    // 检查Fabric组件是否存在
    global.nativeFabricUIManager !== undefined ||
    // 检查其他新架构标识
    (global.RN$Bridgeless !== undefined && global.RN$Bridgeless === true);
    
  return isNewArch ? '新架构 (Fabric)' : '旧架构 (Paper)';
};

// 用于创建随机颜色
const generateRandomColor = () => {
  const r = Math.floor(Math.random() * 200 + 55);
  const g = Math.floor(Math.random() * 200 + 55);
  const b = Math.floor(Math.random() * 200 + 55);
  return `rgb(${r}, ${g}, ${b})`;
};

// 简化数据生成函数,增加用于动画的数据
const generateSimpleItems = (count: number) => {
  return Array(count)
    .fill(0)
    .map((_, index) => ({
      id: `item-${index}`,
      title: `Item ${index}`,
      description: `This is a simple description for item ${index}. We're testing the performance of React Native with a large list of ${count} items.`,
      imageUrl: `https://picsum.photos/id/${(index % 100) + 1}/200/200`,
      color: generateRandomColor(),
      animationBaseValue: Math.random(), // 用于动画的随机初始值
      tags: Array(5).fill(0).map((_, i) => `Tag ${i+1}`),
    }));
};

// 一个频繁更新的子组件
const AnimatedProgressBar = ({ value, color }) => {
  const [animatedValue] = useState(new Animated.Value(0));
  const [counter, setCounter] = useState(0);
  
  // 创建平滑动画
  useEffect(() => {
    Animated.timing(animatedValue, {
      toValue: value,
      duration: 500,
      useNativeDriver: true,
      easing: Easing.inOut(Easing.quad),
    }).start();
    
    // 持续更新一个计数器来制造额外的渲染负担
    const interval = setInterval(() => {
      setCounter(prev => (prev + 1) % 1000);
    }, 100);
    
    return () => clearInterval(interval);
  }, [value]);
  
  return (
    <View style={{ height: 6, width: '100%', backgroundColor: '#e0e0e0', borderRadius: 3, overflow: 'hidden', marginTop: 4 }}>
      <Animated.View 
        style={{ 
          height: '100%', 
          width: '100%', 
          backgroundColor: color,
          transform: [{ 
            scaleX: animatedValue 
          }],
          opacity: 0.7 + ((counter % 30) / 100), // 轻微改变不透明度
          transformOrigin: 'left',
        }} 
      />
    </View>
  );
};

// 计算密集型组件 - 模拟复杂计算并频繁更新
const ComplexCalculation = ({ seed }) => {
  const [result, setResult] = useState(0);
  
  useEffect(() => {
    const interval = setInterval(() => {
      // 计算密集型操作,模拟密集JS计算
      let value = 0;
      for (let i = 0; i < 200; i++) {
        value += Math.sin(i * seed * Date.now() % 10) * Math.cos(i);
      }
      setResult(value);
    }, 300);
    
    return () => clearInterval(interval);
  }, [seed]);
  
  return (
    <Text style={styles.calculationResult}>
      计算结果: {result.toFixed(2)}
    </Text>
  );
};

// 频繁更新的标签列表,具有横向滚动
const TagsList = ({ tags, baseColor }) => {
  const [selectedIndex, setSelectedIndex] = useState(0);
  
  useEffect(() => {
    const interval = setInterval(() => {
      setSelectedIndex(prev => (prev + 1) % tags.length);
    }, 1000);
    
    return () => clearInterval(interval);
  }, [tags.length]);
  
  // 计算标签颜色
  const getTagColor = (index) => {
    if (index === selectedIndex) {
      return baseColor;
    }
    // 降低亮度的颜色
    const color = baseColor.replace('rgb', 'rgba').replace(')', ', 0.5)');
    return color;
  };
  
  return (
    <ScrollView 
      horizontal 
      showsHorizontalScrollIndicator={false}
      style={styles.tagsContainer}
      contentContainerStyle={{ paddingVertical: 4 }}
    >
      {tags.map((tag, index) => (
        <View 
          key={index}
          style={[
            styles.tag,
            { backgroundColor: getTagColor(index) }
          ]}
        >
          <Text style={styles.tagText}>{tag}</Text>
        </View>
      ))}
    </ScrollView>
  );
};

// 复杂的列表项组件,包含多个子组件和动画
const ComplexListItem = React.memo(({ item, index }: any) => {
  const [imageLoaded, setImageLoaded] = useState(false);
  
  // 模拟与本地代码的频繁交互
  useEffect(() => {
    const interval = setInterval(() => {
      // 在真实场景中这会触发原生模块调用
      NativeModules.DeviceInfo?.getConstants();
    }, 500);
    
    return () => clearInterval(interval);
  }, []);
  
  // 计算动画进度值
  const progressValue = (index % 10) / 10 + item.animationBaseValue / 2;

  return (
    <View
      style={[
        styles.item,
        { 
          borderLeftColor: item.color,
          borderLeftWidth: 4,
        },
      ]}
    >
      <View style={styles.imageContainer}>
        {!imageLoaded && <ActivityIndicator style={styles.loader} />}
        <Image
          source={{ uri: item.imageUrl }}
          style={styles.image}
          onLoad={() => setImageLoaded(true)}
        />
        <View style={[styles.imageOverlay, { backgroundColor: `${item.color}88` }]}>
          <Text style={styles.overlayText}>{index}</Text>
        </View>
      </View>
      
      <View style={styles.content}>
        <Text style={styles.title}>{item.title}</Text>
        <Text style={styles.description} numberOfLines={2}>{item.description}</Text>
        
        {/* 添加动画进度条 */}
        <AnimatedProgressBar value={progressValue} color={item.color} />
        
        {/* 添加复杂计算组件 */}
        <ComplexCalculation seed={item.animationBaseValue} />
        
        {/* 添加动态标签列表 */}
        <TagsList tags={item.tags} baseColor={item.color} />
      </View>
    </View>
  );
});

// 主组件
export default function ListPerformanceTest() {
  // 使用1000条数据即可看到差异
  const [data] = useState(() => generateSimpleItems(100));
  
  return (
    <SafeAreaView style={styles.container}>
      <View style={styles.header}>
        <Text style={styles.headerTitle}>架构性能测试列表3 (1000条)</Text>
        <Text style={styles.architecture}>
          架构: {checkArchitecture()}
        </Text>
      </View>
      
      <FlatList
        style={styles.list}
        data={data}
        renderItem={({ item, index }) => (
          <ComplexListItem item={item} index={index} />
        )}
        keyExtractor={item => item.id}
        windowSize={21}
        initialNumToRender={10}
        maxToRenderPerBatch={5}
        updateCellsBatchingPeriod={50}
        removeClippedSubviews={true}
        getItemLayout={(data, index) => (
          {length: 160, offset: 160 * index, index}
        )}
        showsVerticalScrollIndicator={true}
        persistentScrollbar={Platform.OS === 'android'}
        indicatorStyle={Platform.OS === 'ios' ? 'black' : undefined}
        fadingEdgeLength={Platform.OS === 'android' ? 50 : undefined}
      />
    </SafeAreaView>
  );
}

// 样式
const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#f5f5f5',
  },
  header: {
    padding: 12,
    backgroundColor: 'white',
    borderBottomWidth: 1,
    borderBottomColor: '#e0e0e0',
    elevation: 4,
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 2 },
    shadowOpacity: 0.1,
    shadowRadius: 2,
  },
  headerTitle: {
    fontSize: 18,
    fontWeight: 'bold',
    marginBottom: 4,
  },
  architecture: {
    fontSize: 14,
    color: '#666',
  },
  list: {
    flex: 1,
  },
  item: {
    backgroundColor: 'white',
    flexDirection: 'row',
    padding: 10,
    marginVertical: 4,
    marginHorizontal: 8,
    borderRadius: 8,
    elevation: 2,
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 1 },
    shadowOpacity: 0.2,
    shadowRadius: 2,
    height: 150,
  },
  imageContainer: {
    width: 120,
    height: 120,
    borderRadius: 6,
    overflow: 'hidden',
    backgroundColor: '#f0f0f0',
    position: 'relative',
  },
  loader: {
    position: 'absolute',
    left: 0,
    top: 0,
    right: 0,
    bottom: 0,
  },
  image: {
    width: '100%',
    height: '100%',
    resizeMode: 'cover',
  },
  imageOverlay: {
    position: 'absolute',
    bottom: 0,
    left: 0,
    right: 0,
    height: 30,
    justifyContent: 'center',
    alignItems: 'center',
  },
  overlayText: {
    color: 'white',
    fontWeight: 'bold',
    fontSize: 16,
  },
  content: {
    flex: 1,
    marginLeft: 12,
    justifyContent: 'space-between',
  },
  title: {
    fontSize: 16,
    fontWeight: 'bold',
    marginBottom: 4,
  },
  description: {
    fontSize: 14,
    color: '#666',
    marginBottom: 4,
  },
  calculationResult: {
    fontSize: 12,
    color: '#555',
    fontStyle: 'italic',
  },
  tagsContainer: {
    marginTop: 4,
    maxHeight: 30,
  },
  tag: {
    paddingHorizontal: 8,
    paddingVertical: 2,
    borderRadius: 12,
    marginRight: 6,
  },
  tagText: {
    fontSize: 10,
    color: 'white',
    fontWeight: 'bold',
  },
  performanceContainer: {
    flexDirection: 'row',
    justifyContent: 'space-around',
    paddingVertical: 6,
    backgroundColor: 'rgba(0, 0, 0, 0.05)',
    borderBottomWidth: 1,
    borderBottomColor: '#ddd',
  },
  performanceText: {
    fontSize: 12,
    color: '#333',
  },
  performanceValue: {
    fontWeight: 'bold',
    fontSize: 12,
  },
}); 

从图中可以看到新老架构,新架构JS和UI的帧率一致,老架构JS帧率快速滑动很低,并且会有白屏现象,主要原因:

  1. 老架构是异步通信,JS和UI线程分离,快速滑动UI线程会占用大量CPU资源,导致JS无法获得足够资源来处理
  2. 新架构使用的是同步通信,可以直接调用原生方法,一帧内完成数据通信,更好的协同

三、JSI

JSI能够实现同步调用的核心原理在于它创建了一个允许JavaScript和C++代码直接交互的机制:

  1. 统一运行时访问:JSI提供了一个抽象层,可以直接访问JavaScript引擎的运行时
  2. 宿主对象(HostObject)机制:C++对象可以作为"宿主对象"直接暴露给JavaScript
  3. 宿主函数(HostFunction)机制:C++函数可以直接注册为JavaScript可调用的函数
  4. 直接内存访问:JSI允许在不序列化的情况下直接访问和操作JavaScript值

具体实现上,JSI通过以下方式实现同步调用:

cpp 复制代码
// C++端定义一个宿主对象
class MyHostObject : public jsi::HostObject {
public:
  jsi::Value get(jsi::Runtime& runtime, const jsi::PropNameID& name) override {
    if (name.utf8(runtime) == "syncMethod") {
      // 返回一个可以从JS同步调用的函数
      return jsi::Function::createFromHostFunction(
        runtime,
        jsi::PropNameID::forAscii(runtime, "syncMethod"),
        1,  // 参数个数
        [](jsi::Runtime& runtime, const jsi::Value& thisVal, const jsi::Value* args, size_t count) {
          // 直接在C++中执行逻辑并返回结果
          return jsi::String::createFromUtf8(runtime, "Result from C++");
        }
      );
    }
    return jsi::Value::undefined();
  }
};

// 将宿主对象安装到JavaScript全局对象
auto myObject = std::make_shared<MyHostObject>();
runtime.global().setProperty(runtime, "nativeModule", jsi::Object::createFromHostObject(runtime, myObject));

在JavaScript中,可以直接同步调用这个方法:

javascript 复制代码
// 直接同步调用C++方法,并立即获得返回值
const result = global.nativeModule.syncMethod();
console.log(result); // "Result from C++"

3.1 为什么JSI能实现同步而Bridge不能

JSI能够实现同步调用而Bridge不能的根本原因有:

  1. 直接内存共享
    • JSI:JavaScript引擎和C++代码共享内存空间,可以直接传递引用
    • Bridge:两边完全隔离,必须通过序列化/反序列化传递数据
  2. 运行时集成级别
    • JSI:在JavaScript引擎的运行时级别集成,可以直接操作JavaScript对象
    • Bridge:在应用层级集成,无法直接操作JavaScript引擎内部对象
  3. 执行模型
    • JSI:可以在同一个线程上执行JavaScript和C++代码
    • Bridge:JavaScript和原生代码在不同线程上执行
  4. 对象生命周期管理
    • JSI:提供了引用计数和垃圾回收机制,使C++对象可以安全地暴露给JavaScript
    • Bridge:没有统一的对象生命周期管理机制

3.2 技术实现示例

以下是JSI如何在底层实现同步调用的简化示例:

  1. 对象引用传递
    当JavaScript调用C++方法时,JSI不会复制或序列化参数,而是直接传递对象的引用:
cpp 复制代码
// JSI实现中的函数调用
jsi::Value callHostFunction(const jsi::Function& func, const jsi::Value& thisVal, const jsi::Value* args, size_t count) {
  // 直接调用宿主函数,传递参数引用
  return hostFunctionImpl(func, thisVal, args, count);
}
  1. 线程模型
    JSI允许在JavaScript线程上直接执行C++代码,避免了线程切换开销:
cpp 复制代码
// 在JavaScript线程上执行C++代码
jsi::Value executeSync(jsi::Runtime& runtime, const std::function<jsi::Value(jsi::Runtime&)>& func) {
  // 直接在当前线程执行,无需切换线程
  return func(runtime);
}
  1. 值的直接访问
    JSI提供了API直接访问JavaScript值,无需序列化:
cpp 复制代码
// 直接访问JavaScript对象的属性
jsi::Value getProperty(jsi::Runtime& runtime, const jsi::Object& obj, const char* name) {
  // 直接从JavaScript对象中获取属性,无需序列化
  return obj.getProperty(runtime, name);
}

总结

JSI能够实现JavaScript和C++之间的同步调用,是因为它从根本上改变了JavaScript引擎与原生代码的集成方式,从应用层的消息传递提升到了运行时级别的直接集成。这种深度集成使得两个环境可以直接共享内存和对象引用,从而实现同步调用。

新架构jsi可以直接引用而老架构只能序列化的真正原因是,老架构的js引擎也支持c++ binding,但是老架构没有用,而是只开放了nativemodule来序列化传递数据,但是新架构通过jsi抽象,把js引擎原有的能力都暴漏给开发者了,所以可以使用同步的方式,

思考:为什么不直接使用JSI而是用的桥通信序列话的方式?

结合AI和自己的思考,我想有以下几个原因:

  1. 序列化实现简单,不需要对JS引擎有深入理解
  2. Android缺少好的JSRuntime来做,并且还要考虑C++中内存问题,RN项目初期的目标是让跨平台整体架构是否能够跑通,正确性,稳定性和开发效率是关键,而非性能优化
  3. 这里引用Donald Knuth来说明下:
    1. We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil. Yet we should not pass up our opportunities in that critical 3%.
    2. 我们应该忽略小的效率问题,大约97%的时间都是如此:过早优化是万恶之源。但我们不应该错过那关键的3%的优化机会。
  4. 我们在做整体系统设计时,重点是先让他跑起来,先完成再完美。

四、TurboModule模块系统

之前我们介绍过,RN旧架构是通过桥来通信的,那官方写的各种桥和我们写的各种桥,就要做Leagy Module,它是基于序列化方式通信的,那我们一起来看下整体module模块是如何工作的以及新老架构的源码吧!

整体调用流程图

4.1 Legacy Module调用源码

shell 复制代码
/**
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @flow strict
 * @format
 */

import type {TurboModule} from '../../../../Libraries/TurboModule/RCTExport';

import * as TurboModuleRegistry from '../../../../Libraries/TurboModule/TurboModuleRegistry';

// 这里是一个手写的规范定义文件
export interface Spec extends TurboModule {
  +getConstants: () => {
    SHORT: number,
    LONG: number,
    TOP: number,
    BOTTOM: number,
    CENTER: number,
  };
  +show: (message: string, duration: number) => void;
  +showWithGravity: (
    message: string,
    duration: number,
    gravity: number,
  ) => void;
  +showWithGravityAndOffset: (
    message: string,
    duration: number,
    gravity: number,
    xOffset: number,
    yOffset: number,
  ) => void;
}

// 1.TurboModuleRegistry
export default (TurboModuleRegistry.getEnforcing<Spec>('ToastAndroid'): Spec);
shell 复制代码
function requireModule<T: TurboModule>(name: string): ?T {
  if (turboModuleProxy != null) {
    // 新架构
    const module: ?T = turboModuleProxy(name);
    if (module != null) {
      return module;
    }
  }

  if (
    global.RN$Bridgeless !== true ||
    global.RN$TurboInterop === true ||
    global.RN$UnifiedNativeModuleProxy === true
  ) {
    // 2.老架构
    const legacyModule: ?T = NativeModules[name];
    if (legacyModule != null) {
      return legacyModule;
    }
  }

  return null;
}
shell 复制代码
let NativeModules: {[moduleName: string]: any, ...} = {};
if (global.nativeModuleProxy) { // 新架构
  NativeModules = global.nativeModuleProxy; 
} else { // 3.老架构
  const bridgeConfig = global.__fbBatchedBridgeConfig;
  invariant(
    bridgeConfig,
    '__fbBatchedBridgeConfig is not set, cannot invoke native modules',
  );

  const defineLazyObjectProperty =
    require('../Utilities/defineLazyObjectProperty').default;
  (bridgeConfig.remoteModuleConfig || []).forEach(
    (config: ModuleConfig, moduleID: number) => {
      // Initially this config will only contain the module name when running in JSC. The actual
      // configuration of the module will be lazily loaded.
      // 4.定义老架构的module对象
      const info = genModule(config, moduleID);
      if (!info) {
        return;
      }

      if (info.module) {
        NativeModules[info.name] = info.module;
      }
      // If there's no module config, define a lazy getter
      else {
        defineLazyObjectProperty(NativeModules, info.name, {
          get: () => loadModule(info.name, moduleID),
        });
      }
    },
  );
}
shell 复制代码
// 5.这个是生成JSModule对象的具体方法
function genMethod(moduleID: number, methodID: number, type: MethodType) {
  let fn = null;
  if (type === 'promise') {
    fn = function promiseMethodWrapper(...args: Array<mixed>) {
      // In case we reject, capture a useful stack trace here.
      /* $FlowFixMe[class-object-subtyping] added when improving typing for
       * this parameters */
      // $FlowFixMe[incompatible-type]
      const enqueueingFrameError: ExtendedError = new Error();
      return new Promise((resolve, reject) => {
        // 如果是Promise方法,则使用这个发送                 
        BatchedBridge.enqueueNativeCall(
          moduleID,
          methodID,
          args,
          data => resolve(data),
          errorData =>
            reject(
              updateErrorWithErrorData(
                (errorData: $FlowFixMe),
                enqueueingFrameError,
              ),
            ),
        );
      });
    };
  } else {
    fn = function nonPromiseMethodWrapper(...args: Array<mixed>) {
      const lastArg = args.length > 0 ? args[args.length - 1] : null;
      const secondLastArg = args.length > 1 ? args[args.length - 2] : null;
      const hasSuccessCallback = typeof lastArg === 'function';
      const hasErrorCallback = typeof secondLastArg === 'function';
      hasErrorCallback &&
        invariant(
          hasSuccessCallback,
          'Cannot have a non-function arg after a function arg.',
        );
      // $FlowFixMe[incompatible-type]
      const onSuccess: ?(mixed) => void = hasSuccessCallback ? lastArg : null;
      // $FlowFixMe[incompatible-type]
      const onFail: ?(mixed) => void = hasErrorCallback ? secondLastArg : null;
      // $FlowFixMe[unsafe-addition]
      const callbackCount = hasSuccessCallback + hasErrorCallback;
      const newArgs = args.slice(0, args.length - callbackCount);
      if (type === 'sync') {
        // 6.如果是同步方法调用这个函数
        return BatchedBridge.callNativeSyncHook(
          moduleID,
          methodID,
          newArgs,
          onFail,
          onSuccess,
        );
      } else {
        // 非同步方法调用这个函数
        BatchedBridge.enqueueNativeCall(
          moduleID,
          methodID,
          newArgs,
          onFail,
          onSuccess,
        );
      }
    };
  }
  // $FlowFixMe[prop-missing]
  fn.type = type;
  return fn;
}
shell 复制代码
// 7.来看异步方法
cruntime_->global().setProperty(
      *runtime_,
      "nativeFlushQueueImmediate",
      Function::createFromHostFunction(
          *runtime_,
          PropNameID::forAscii(*runtime_, "nativeFlushQueueImmediate"),
          1,
          [this](
              jsi::Runtime&,
              const jsi::Value&,
              const jsi::Value* args,
              size_t count) {
            if (count != 1) {
              throw std::invalid_argument(
                  "nativeFlushQueueImmediate arg count must be 1");
            }
            // 8.真正调用地方
            callNativeModules(args[0], false);
            return Value::undefined();
          }));
cpp 复制代码
void JSIExecutor::callNativeModules(const Value& queue, bool isEndOfBatch) {
    TraceSection s("JSIExecutor::callNativeModules");
    // If this fails, you need to pass a fully functional delegate with a
    // module registry to the factory/ctor.
    CHECK(delegate_) << "Attempting to use native modules without a delegate";
    #if 0 // maybe useful for debugging
    std::string json = runtime_->global().getPropertyAsObject(*runtime_, "JSON")
    .getPropertyAsFunction(*runtime_, "stringify").call(*runtime_, queue)
    .getString(*runtime_).utf8(*runtime_);
    #endif
    BridgeNativeModulePerfLogger::asyncMethodCallBatchPreprocessStart();
    //9.
    delegate_->callNativeModules(
        *this, dynamicFromValue(*runtime_, queue), isEndOfBatch);
}
cpp 复制代码
void callNativeModules(
[[maybe_unused]] JSExecutor& executor,
folly::dynamic&& calls,
bool isEndOfBatch) override {
    CHECK(m_registry || calls.empty())
        << "native module calls cannot be completed with no native modules";
    m_batchHadNativeModuleOrTurboModuleCalls =
        m_batchHadNativeModuleOrTurboModuleCalls || !calls.empty();

    std::vector<MethodCall> methodCalls = parseMethodCalls(std::move(calls));
    BridgeNativeModulePerfLogger::asyncMethodCallBatchPreprocessEnd(
        (int)methodCalls.size());

    // An exception anywhere in here stops processing of the batch.  This
    // was the behavior of the Android bridge, and since exception handling
    // terminates the whole bridge, there's not much point in continuing.
    for (auto& call : methodCalls) {
        // 10
        m_registry->callNativeMethod(
            call.moduleId, call.methodId, std::move(call.arguments), call.callId);
    }
    if (isEndOfBatch) {
        // onBatchComplete will be called on the native (module) queue, but
        // decrementPendingJSCalls will be called sync. Be aware that the bridge
        // may still be processing native calls when the bridge idle signaler
        // fires.
        if (m_batchHadNativeModuleOrTurboModuleCalls) {
            m_callback->onBatchComplete();
            m_batchHadNativeModuleOrTurboModuleCalls = false;
        }
        m_callback->decrementPendingJSCalls();
    }
}

void ModuleRegistry::callNativeMethod(
    unsigned int moduleId,
    unsigned int methodId,
    folly::dynamic&& params,
    int callId) {
  if (moduleId >= modules_.size()) {
    throw std::runtime_error(folly::to<std::string>(
        "moduleId ", moduleId, " out of range [0..", modules_.size(), ")"));
  }
  //11
  modules_[moduleId]->invoke(methodId, std::move(params), callId);
}

// JavaMethodWrapper.cpp
void JavaNativeModule::invoke(
    unsigned int reactMethodId,
    folly::dynamic&& params,
    int callId) {
  // 12. 发送消息
  messageQueueThread_->runOnQueue(
      [this, reactMethodId, params = std::move(params), callId] {
        static auto invokeMethod =
            wrapper_->getClass()
                ->getMethod<void(jint, ReadableNativeArray::javaobject)>(
                    "invoke");
#ifdef WITH_FBSYSTRACE
        if (callId != -1) {
          fbsystrace_end_async_flow(TRACE_TAG_REACT_APPS, "native", callId);
        }
#endif
        invokeMethod(
            wrapper_,
            static_cast<jint>(reactMethodId),
            ReadableNativeArray::newObjectCxxArgs(std::move(params)).get());
      });
}

// JavaMethodWrapper.java
@DoNotStrip
  public void invoke(int methodId, ReadableNativeArray parameters) {
    if (methodId >= mMethods.size()) {
      return;
    }
    //13.
    mMethods.get(methodId).invoke(mJSInstance, parameters);
  }

// NativeModuleREgistryBuilder.kt
public fun processPackage(reactPackage: ReactPackage) {
    // We use an iterable instead of an iterator here to ensure thread safety, and that this list
    // cannot be modified
    val moduleHolders =
        @Suppress("DEPRECATION")
        if (reactPackage is LazyReactPackage) {
          reactPackage.getNativeModuleIterator(reactApplicationContext)
        } else if (reactPackage is BaseReactPackage) {
          reactPackage.getNativeModuleIterator(reactApplicationContext)
        } else {
          ReactPackageHelper.getNativeModuleIterator(reactPackage, reactApplicationContext)
        }
    for (moduleHolder in moduleHolders) {
      val name = moduleHolder.name
      val existingNativeModule = modules[name]
      if (existingNativeModule != null) {
    }
}

// NativeToJsBridge.cpp,最后Java侧调用Promise会执行到这里,
void NativeToJsBridge::invokeCallback(
    double callbackId,
    folly::dynamic&& arguments) {
  int systraceCookie = -1;
#ifdef WITH_FBSYSTRACE
  systraceCookie = m_systraceCookie++;
  FbSystraceAsyncFlow::begin(
      TRACE_TAG_REACT_CXX_BRIDGE, "<callback>", systraceCookie);
#endif

  runOnExecutorQueue(
      [this, callbackId, arguments = std::move(arguments), systraceCookie](
          JSExecutor* executor) {
        if (m_applicationScriptHasFailure) {
          LOG(ERROR)
              << "Attempting to call JS callback on a bad application bundle: "
              << callbackId;
          throw std::runtime_error(
              "Attempting to invoke JS callback on a bad application bundle.");
        }

这上面就是整体JS到Native的调用过程,整体流程还是很长的。

4.2 Turbo Module调用源码

shell 复制代码
runtime.global().setProperty(
        runtime,
        "__turboModuleProxy", // 1.挂载到js的global对象上
        jsi::Function::createFromHostFunction(
            runtime,
            jsi::PropNameID::forAscii(runtime, "__turboModuleProxy"),
            1,
            [binding = TurboModuleBinding(
                 runtime,
                 std::move(moduleProvider),
                 longLivedObjectCollection)](
                jsi::Runtime& rt,
                const jsi::Value& /*thisVal*/,
                const jsi::Value* args,
                size_t count) {
              if (count < 1) {
                throw std::invalid_argument(
                    "__turboModuleProxy must be called with at least 1 argument");
              }
              std::string moduleName = args[0].getString(rt).utf8(rt);
              return binding.getModule(rt, moduleName);
            }));
    return;
shell 复制代码
jsi::Value TurboModuleBinding::getModule(
    jsi::Runtime& runtime,
    const std::string& moduleName) const {
  std::shared_ptr<TurboModule> module;
  {
    TraceSection s("TurboModuleBinding::moduleProvider", "module", moduleName);
    module = moduleProvider_(moduleName);
  }
  if (module) {
    // What is jsRepresentation? A cache for the TurboModule's properties
    // Henceforth, always return the cache (i.e: jsRepresentation) to JavaScript
    //
    // If a jsRepresentation is found on the TurboModule, return it.
    //
    // Note: TurboModules are cached by name in TurboModuleManagers. Hence,
    // jsRepresentation is also cached by by name by the TurboModuleManager
    auto& weakJsRepresentation = module->jsRepresentation_;
    if (weakJsRepresentation) {
      auto jsRepresentation = weakJsRepresentation->lock(runtime);
      if (!jsRepresentation.isUndefined()) {
        return jsRepresentation;
      }
    }

    // Status: No jsRepresentation found on TurboModule
    // Create a brand new jsRepresentation, and attach it to TurboModule
    jsi::Object jsRepresentation(runtime);
    weakJsRepresentation =
        std::make_unique<jsi::WeakObject>(runtime, jsRepresentation);

    // Lazily populate the jsRepresentation, on property access.
    //
    // How does this work?
    //   1. Initially jsRepresentation is empty: {}
    //   2. If property lookup on jsRepresentation fails, the JS runtime will
    //   search jsRepresentation's prototype: jsi::Object(TurboModule).
    //   3. TurboModule::get(runtime, propKey) executes. This creates the
    //   property, caches it on jsRepresentation, then returns it to
    //   JavaScript.
    //  2. 直接看这里,它是通过jsi创建了一个hostObject,这个就像当于把native端的module注入到了这个js对象上
    //  3. 翻译一下这里的逻辑是如何做的,jsRepresentation是作为native侧的js对象,它使用的是懒加载的方式,只有第一次用到了这个module的方法才会创建
    //  创建的代码在TurboModule::get(runtime, propKey)这里面
    auto hostObject =
        jsi::Object::createFromHostObject(runtime, std::move(module));
    jsRepresentation.setProperty(runtime, "__proto__", std::move(hostObject));

    return jsRepresentation;
  } else {
    return jsi::Value::null();
  }
}
shell 复制代码
class JSI_EXPORT TurboModule : public jsi::HostObject {
 public:
  TurboModule(std::string name, std::shared_ptr<CallInvoker> jsInvoker);

  // DO NOT OVERRIDE - it will become final in a future release.
  // This method provides automatic caching of properties on the TurboModule's
  // JS representation. To customize lookup of properties, override `create`.
  // Note: keep this method declared inline to avoid conflicts
  // between RTTI and non-RTTI compilation units
  // 
  // 4.那就看下这里面的懒加载逻辑
  jsi::Value get(jsi::Runtime& runtime, const jsi::PropNameID& propName)
      override {
    auto prop = create(runtime, propName);
    // If we have a JS wrapper, cache the result of this lookup
    // We don't cache misses, to allow for methodMap_ to dynamically be
    // extended
    if (jsRepresentation_ && !prop.isUndefined()) {
      // 5.直接将native的module绑定到这个jsRepresentation_对象上
      jsRepresentation_->lock(runtime).asObject(runtime).setProperty(
          runtime, propName, prop);
    }
    return prop;
  }

可以看出来它是利用了jsi的机制,直接在引擎层面建立了module的对应关系,这样js侧直接调用即可,他就是引擎层给js的对象了。

主要基于的就是JS的原型链逻辑,当前属性没有就去找__proto__,这个就是就会走到get方法里,此时会创建一个新的属性到jsRepresentation_对象上,这样下次js再方法就可以直接返回了。

以上TurboModule就分析完了,接下来再看下渲染器吧!

五、Fabric渲染

刚才所说的,同步,优先级,并发渲染都是渲染器来实现的,RN中的渲染器叫做Fabric。

老架构中的渲染系统,渲染那树的逻辑及优化都是针对单个平台实现的,而当前的渲染器则是通过共享一个核心C++实现的。

那说到渲染,我们都知道类似于这种响应式的UI开发,都是通过虚拟DOM的形式来渲染的,那我们直接来看看它的三个树都有啥吧。

5.1 Element Tree

纯JS逻辑,我们所有写的RN标签就是Element,最后会变成一个视图树

shell 复制代码
// Element Tree的结构
const elementTree = {
  type: 'View',
  props: { 
    style: { backgroundColor: 'red', width: 100, height: 100 },
    onPress: () => console.log('clicked')
  },
  children: [
    {
      type: 'Text',
      props: { children: 'Hello World' },
      children: []
    }
  ]
};

Diff算法在这里:

  • 同级比较:只比较同一层级的节点
  • key优化:使用key属性优化列表diff
  • 类型判断:type不同直接替换整个子树
shell 复制代码
// React的reconciliation算法
function reconcileChildren(current, workInProgress, nextChildren) {
  if (current === null) {
    // 首次渲染,直接创建
    workInProgress.child = mountChildFibers(workInProgress, null, nextChildren);
  } else {
    // 更新渲染,执行diff
    workInProgress.child = reconcileChildFibers(
      workInProgress, 
      current.child, 
      nextChildren
    );
  }
}

感兴趣的可以推荐看这个pomb.us/build-your-...,实现自己的React。

5.2 Shadow Tree

www.yogalayout.dev/

C++层逻辑,使用Yoga库来计算视图树的逻辑,Yoga负责样式计算和布局算法(flex布局),同步测量

原来是使用的是JNI的方式,有Java到C++的数据转换,现在新架构直接使用c++在c++层操作yoga

Java侧无需再维护YogaNode视图树对象

老架构是使用的Java来维护的ShadowTree,现在统一到Fabric,c++侧维护

整体新老架构shadow tree对比图

我们以创建一个View为例子看下具体如何实现的吧

shell 复制代码
  //1.js侧会调用到此,创建一个view
@ReactMethod
  public void createView(int tag, String className, int rootViewTag, ReadableMap props) {
    if (DEBUG) {
      String message =
          "(UIManager.createView) tag: " + tag + ", class: " + className + ", props: " + props;
      FLog.d(ReactConstants.TAG, message);
      PrinterHolder.getPrinter().logMessage(ReactDebugOverlayTags.UI_MANAGER, message);
    }
    mUIImplementation.createView(tag, className, rootViewTag, props);
  }
shell 复制代码
public void createView(int tag, String className, int rootViewTag, ReadableMap props) {
    if (!mViewOperationsEnabled) {
      return;
    }

    synchronized (uiImplementationThreadLock) {
      ReactShadowNode cssNode = createShadowNode(className);
      ReactShadowNode rootNode = mShadowNodeRegistry.getNode(rootViewTag);
      Assertions.assertNotNull(rootNode, "Root node with tag " + rootViewTag + " doesn't exist");
      cssNode.setReactTag(tag); // Thread safety needed here
      cssNode.setViewClassName(className);
      cssNode.setRootTag(rootNode.getReactTag());
      cssNode.setThemedContext(rootNode.getThemedContext());

      mShadowNodeRegistry.addNode(cssNode);

      ReactStylesDiffMap styles = null;
      if (props != null) {
        styles = new ReactStylesDiffMap(props);
        cssNode.updateProperties(styles);
      }
      // 2. 实际处理
      handleCreateView(cssNode, rootViewTag, styles);
    }
  }
}
shell 复制代码
protected void handleCreateView(
    ReactShadowNode cssNode, int rootViewTag, @Nullable ReactStylesDiffMap styles) {
  if (!cssNode.isVirtual()) {
    // 3. mNativeViewHierarchyOptimizer处理
    mNativeViewHierarchyOptimizer.handleCreateView(cssNode, cssNode.getThemedContext(), styles);
  }
}
shell 复制代码
public void handleCreateView(
      ReactShadowNode node,
      ThemedReactContext themedContext,
      @Nullable ReactStylesDiffMap initialProps) {
    if (!ENABLED) {
      assertNodeSupportedWithoutOptimizer(node);
      int tag = node.getReactTag();
      mUIViewOperationQueue.enqueueCreateView(
          themedContext, tag, node.getViewClass(), initialProps);
      return;
    }

    boolean isLayoutOnly =
        node.getViewClass().equals(ViewProps.VIEW_CLASS_NAME)
            && isLayoutOnlyAndCollapsable(initialProps);
    node.setIsLayoutOnly(isLayoutOnly);

    if (node.getNativeKind() != NativeKind.NONE) {
      // 4. 将创建作为命令添加到队列中去
      mUIViewOperationQueue.enqueueCreateView(
          themedContext, node.getReactTag(), node.getViewClass(), initialProps);
    }
  }
shell 复制代码
// 5. commit 提交更新
public void dispatchViewUpdates(int batchId) {
  SystraceMessage.beginSection(
          Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "UIImplementation.dispatchViewUpdates")
      .arg("batchId", batchId)
      .flush();
  final long commitStartTime = SystemClock.uptimeMillis();
  try {
    updateViewHierarchy();
    mNativeViewHierarchyOptimizer.onBatchComplete();
    // 6. 分发view更新
    mOperationsQueue.dispatchViewUpdates(batchId, commitStartTime, mLastCalculateLayoutTime);
  
  } finally {
    Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
  }
}
shell 复制代码
public void dispatchViewUpdates(
      final int batchId, final long commitStartTime, final long layoutTime) {
      //....
synchronized (mDispatchRunnablesLock) {
        Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
        // 7. 所有更新加到mDispatchUIRunnables中
        mDispatchUIRunnables.add(runOperations);
      }
      //....
}
shell 复制代码
@Override
    public void doFrameGuarded(long frameTimeNanos) {
      if (mIsInIllegalUIState) {
        FLog.w(
            ReactConstants.TAG,
            "Not flushing pending UI operations because of previously thrown Exception");
        return;
      }

      Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "dispatchNonBatchedUIOperations");
      try {
        // 8.1  分发操作
        dispatchPendingNonBatchedOperations(frameTimeNanos);
      } finally {
        Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
      }
      // 8.2  一样的分发操作
      flushPendingBatches();

      ReactChoreographer.getInstance()
          .postFrameCallback(ReactChoreographer.CallbackType.DISPATCH_UI, this);
    }

从这里我们就可以看出来了,它是通过js序列化消息传递到客户端的UIManager,然后也通过队列的方式进行UI相关命令缓存,等到vsync信号后开始渲染

shell 复制代码
public synchronized void createView(
      ThemedReactContext themedContext,
      int tag,
      String className,
      @Nullable ReactStylesDiffMap initialProps) {
    if (DEBUG_MODE) {
      FLog.d(
          TAG,
          "createView[%d]: %s %s",
          tag,
          className,
          (initialProps != null ? initialProps.toString() : "<null>"));
    }
    UiThreadUtil.assertOnUiThread();
    SystraceMessage.beginSection(
            Systrace.TRACE_TAG_REACT_VIEW, "NativeViewHierarchyManager_createView")
        .arg("tag", tag)
        .arg("className", className)
        .flush();
    try {
      // 9 通过viewmanger找到对应的真实view,然后创建绑定
      ViewManager viewManager = mViewManagers.get(className);

      View view =
          viewManager.createView(tag, themedContext, initialProps, null, mJSResponderHandler);
      mTagsToViews.put(tag, view);
      mTagsToViewManagers.put(tag, viewManager);
    } finally {
      Systrace.endSection(Systrace.TRACE_TAG_REACT_VIEW);
    }
  }

从这里我们就可以看出来它主题逻辑还是由Java侧计算渲染的。

5.3 新架构Fabric渲染

如果从渲染的角度来看,结合Vysnc来看:

Fabric架构也是通过的JSI来做的,它在JS侧的定义为

shell 复制代码
/**
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @flow strict-local
 * @format
 */

'use strict';

import type {
  MeasureInWindowOnSuccessCallback,
  MeasureLayoutOnSuccessCallback,
  MeasureOnSuccessCallback,
} from '../../src/private/types/HostInstance';
import type {NativeElementReference} from '../../src/private/webapis/dom/nodes/specs/NativeDOM';
import type {
  InternalInstanceHandle,
  LayoutAnimationConfig,
  Node,
} from '../Renderer/shims/ReactNativeTypes';
import type {RootTag} from '../Types/RootTagTypes';

import defineLazyObjectProperty from '../Utilities/defineLazyObjectProperty';

export type NodeSet = Array<Node>;
export type NodeProps = {...};
export interface Spec {
  +createNode: (
    reactTag: number,
    viewName: string,
    rootTag: RootTag,
    props: NodeProps,
    instanceHandle: InternalInstanceHandle,
  ) => Node;
  +cloneNode: (node: Node) => Node;
  +cloneNodeWithNewChildren: (node: Node) => Node;
  +cloneNodeWithNewProps: (node: Node, newProps: NodeProps) => Node;
  +cloneNodeWithNewChildrenAndProps: (node: Node, newProps: NodeProps) => Node;
  +createChildSet: (rootTag: RootTag) => NodeSet;
  +appendChild: (parentNode: Node, child: Node) => Node;
  +appendChildToSet: (childSet: NodeSet, child: Node) => void;
  +completeRoot: (rootTag: RootTag, childSet: NodeSet) => void;
  +measure: (
    node: Node | NativeElementReference,
    callback: MeasureOnSuccessCallback,
  ) => void;
  +measureInWindow: (
    node: Node | NativeElementReference,
    callback: MeasureInWindowOnSuccessCallback,
  ) => void;
  +measureLayout: (
    node: Node | NativeElementReference,
    relativeNode: Node | NativeElementReference,
    onFail: () => void,
    onSuccess: MeasureLayoutOnSuccessCallback,
  ) => void;
  +configureNextLayoutAnimation: (
    config: LayoutAnimationConfig,
    callback: () => void, // check what is returned here
    errorCallback: () => void,
  ) => void;
  +sendAccessibilityEvent: (node: Node, eventType: string) => void;
  +findShadowNodeByTag_DEPRECATED: (reactTag: number) => ?Node;
  +setNativeProps: (
    node: Node | NativeElementReference,
    newProps: NodeProps,
  ) => void;
  +dispatchCommand: (
    node: Node,
    commandName: string,
    args: Array<mixed>,
  ) => void;
  +findNodeAtPoint: (
    node: Node,
    locationX: number,
    locationY: number,
    callback: (instanceHandle: ?InternalInstanceHandle) => void,
  ) => void;
  +compareDocumentPosition: (
    node: Node | NativeElementReference,
    otherNode: Node | NativeElementReference,
  ) => number;
  +getBoundingClientRect: (
    node: Node | NativeElementReference,
    includeTransform: boolean,
  ) => ?[
    /* x: */ number,
    /* y: */ number,
    /* width: */ number,
    /* height: */ number,
  ];
}

let nativeFabricUIManagerProxy: ?Spec;

// This is a list of all the methods in global.nativeFabricUIManager that we'll
// cache in JavaScript, as the current implementation of the binding
// creates a new host function every time methods are accessed.
const CACHED_PROPERTIES = [
  'createNode', // 1. 创建node
  'cloneNode',
  'cloneNodeWithNewChildren',
  'cloneNodeWithNewProps',
  'cloneNodeWithNewChildrenAndProps',
  'createChildSet',
  'appendChild',
  'appendChildToSet',
  'completeRoot',
  'measure',
  'measureInWindow',
  'measureLayout',
  'configureNextLayoutAnimation',
  'sendAccessibilityEvent',
  'findShadowNodeByTag_DEPRECATED',
  'setNativeProps',
  'dispatchCommand',
  'compareDocumentPosition',
  'getBoundingClientRect',
];

// This is exposed as a getter because apps using the legacy renderer AND
// Fabric can define the binding lazily. If we evaluated the global and cached
// it in the module we might be caching an `undefined` value before it is set.
export function getFabricUIManager(): ?Spec {
  if (
    nativeFabricUIManagerProxy == null &&
    global.nativeFabricUIManager != null
  ) {
    nativeFabricUIManagerProxy = createProxyWithCachedProperties(
      global.nativeFabricUIManager,
      CACHED_PROPERTIES,
    );
  }
  return nativeFabricUIManagerProxy;
}

/**
 *
 * Returns an object that caches the specified properties the first time they
 * are accessed, and falls back to the original object for other properties.
 */
function createProxyWithCachedProperties(
  implementation: Spec,
  propertiesToCache: $ReadOnlyArray<string>,
): Spec {
  const proxy = Object.create(implementation);
  for (const propertyName of propertiesToCache) {
    defineLazyObjectProperty(proxy, propertyName, {
      // $FlowExpectedError[prop-missing]
      get: () => implementation[propertyName],
    });
  }
  return proxy;
}
cpp 复制代码
if (methodName == "createNode") {
    auto paramCount = 5;
    return jsi::Function::createFromHostFunction(
        runtime,
        name,
        paramCount,
        [uiManager, methodName, paramCount](
            jsi::Runtime& runtime,
            const jsi::Value& /*thisValue*/,
            const jsi::Value* arguments,
            size_t count) -> jsi::Value {
          try {
            validateArgumentCount(runtime, methodName, paramCount, count);

            auto instanceHandle =
                instanceHandleFromValue(runtime, arguments[4], arguments[0]);
            if (!instanceHandle) {
              react_native_assert(false);
              return jsi::Value::undefined();
            }

            return valueFromShadowNode(
                runtime,
                uiManager->createNode( //2.创建node
                    tagFromValue(arguments[0]),
                    stringFromValue(runtime, arguments[1]),
                    surfaceIdFromValue(runtime, arguments[2]),
                    RawProps(runtime, arguments[3]),
                    std::move(instanceHandle)),
                true);
          } catch (const std::logic_error& ex) {
            LOG(FATAL) << "logic_error in createNode: " << ex.what();
          }
        });
  }
cpp 复制代码
std::shared_ptr<ShadowNode> UIManager::createNode(
    Tag tag,
    const std::string& name,
    SurfaceId surfaceId,
    RawProps rawProps,
    InstanceHandle::Shared instanceHandle) const {
  TraceSection s("UIManager::createNode", "componentName", name);

  auto& componentDescriptor = componentDescriptorRegistry_->at(name);
  auto fallbackDescriptor =
      componentDescriptorRegistry_->getFallbackComponentDescriptor();

  PropsParserContext propsParserContext{surfaceId, *contextContainer_.get()};

  auto family = componentDescriptor.createFamily(
      {tag, surfaceId, std::move(instanceHandle)});
  const auto props = componentDescriptor.cloneProps(
      propsParserContext, nullptr, std::move(rawProps));
  const auto state = componentDescriptor.createInitialState(props, family);

  //3. 创建ShadowNode
  auto shadowNode = componentDescriptor.createShadowNode(
      ShadowNodeFragment{
          .props = fallbackDescriptor != nullptr &&
                  fallbackDescriptor->getComponentHandle() ==
                      componentDescriptor.getComponentHandle()
              ? componentDescriptor.cloneProps(
                    propsParserContext,
                    props,
                    RawProps(folly::dynamic::object("name", name)))
              : props,
          .children = ShadowNodeFragment::childrenPlaceholder(),
          .state = state,
      },
      family);

  if (delegate_ != nullptr) {
    delegate_->uiManagerDidCreateShadowNode(*shadowNode);
  }
  if (leakChecker_) {
    leakChecker_->uiManagerDidCreateShadowNodeFamily(family);
  }

  return shadowNode;
}
cpp 复制代码
if (methodName == "completeRoot") {// 4. 一次渲染周期完成,通知Fabric渲染完成
    auto paramCount = 2;
    return jsi::Function::createFromHostFunction(
        runtime,
        name,
        paramCount,
        [uiManager, methodName, paramCount](
            jsi::Runtime& runtime,
            const jsi::Value& /*thisValue*/,
            const jsi::Value* arguments,
            size_t count) -> jsi::Value {
          validateArgumentCount(runtime, methodName, paramCount, count);

          auto runtimeSchedulerBinding =
              RuntimeSchedulerBinding::getBinding(runtime);
          auto surfaceId = surfaceIdFromValue(runtime, arguments[0]);

          auto shadowNodeList = shadowNodeListFromValue(runtime, arguments[1]);
          //5. 实际触发渲染
          uiManager->completeSurface(
              surfaceId,
              shadowNodeList,
              {.enableStateReconciliation = true, .mountSynchronously = false});

          return jsi::Value::undefined();
        });
  }
cpp 复制代码
void UIManager::completeSurface(
    SurfaceId surfaceId,
    const ShadowNode::UnsharedListOfShared& rootChildren,
    ShadowTree::CommitOptions commitOptions) {
  TraceSection s("UIManager::completeSurface", "surfaceId", surfaceId);

  shadowTreeRegistry_.visit(surfaceId, [&](const ShadowTree& shadowTree) {
    // 6.提交commit
    auto result = shadowTree.commit(
        [&](const RootShadowNode& oldRootShadowNode) {
          return std::make_shared<RootShadowNode>(
              oldRootShadowNode,
              ShadowNodeFragment{
                  .props = ShadowNodeFragment::propsPlaceholder(),
                  .children = rootChildren,
              });
        },
        commitOptions);

    if (result == ShadowTree::CommitStatus::Succeeded &&
        lazyShadowTreeRevisionConsistencyManager_ != nullptr) {
      // It's safe to update the visible revision of the shadow tree immediately
      // after we commit a specific one.
      lazyShadowTreeRevisionConsistencyManager_->updateCurrentRevision(
          surfaceId, shadowTree.getCurrentRevision().rootShadowNode);
    }
  });
}
cpp 复制代码
//7.针对于shadowtree的新老版本进行对比
CommitStatus ShadowTree::tryCommit(
    const ShadowTreeCommitTransaction& transaction,
    const CommitOptions& commitOptions) const {
  TraceSection s("ShadowTree::commit");

  auto telemetry = TransactionTelemetry{};
  telemetry.willCommit();

  CommitMode commitMode;
  auto oldRevision = ShadowTreeRevision{};
  auto newRevision = ShadowTreeRevision{};

  {
    // Reading `currentRevision_` in shared manner.
    std::shared_lock lock(commitMutex_);
    commitMode = commitMode_;
    oldRevision = currentRevision_;
  }

  const auto& oldRootShadowNode = oldRevision.rootShadowNode;
  auto newRootShadowNode = transaction(*oldRevision.rootShadowNode);

  if (!newRootShadowNode) {
    return CommitStatus::Cancelled;
  }

  if (commitOptions.enableStateReconciliation) {
    //8.真正的shadowtree的diff算法在ProgressState
    auto updatedNewRootShadowNode =
        progressState(*newRootShadowNode, *oldRootShadowNode);
    if (updatedNewRootShadowNode) {
      newRootShadowNode =
          std::static_pointer_cast<RootShadowNode>(updatedNewRootShadowNode);
    }
  }

  // Run commit hooks.
  newRootShadowNode = delegate_.shadowTreeWillCommit(
      *this, oldRootShadowNode, newRootShadowNode);

  if (!newRootShadowNode) {
    return CommitStatus::Cancelled;
  }

  // Layout nodes.
  std::vector<const LayoutableShadowNode*> affectedLayoutableNodes{};
  affectedLayoutableNodes.reserve(1024);

  telemetry.willLayout();
  telemetry.setAsThreadLocal();
  //9.进行layout
  newRootShadowNode->layoutIfNeeded(&affectedLayoutableNodes);
  telemetry.unsetAsThreadLocal();
  telemetry.didLayout(static_cast<int>(affectedLayoutableNodes.size()));

  {
    // Updating `currentRevision_` in unique manner if it hasn't changed.
    std::unique_lock lock(commitMutex_);

    if (currentRevision_.number != oldRevision.number) {
      return CommitStatus::Failed;
    }

    auto newRevisionNumber = currentRevision_.number + 1;

    {
      std::scoped_lock dispatchLock(EventEmitter::DispatchMutex());
      updateMountedFlag(
          currentRevision_.rootShadowNode->getChildren(),
          newRootShadowNode->getChildren());
    }

    telemetry.didCommit();
    telemetry.setRevisionNumber(static_cast<int>(newRevisionNumber));

    // Seal the shadow node so it can no longer be mutated
    // Does nothing in release.
    newRootShadowNode->sealRecursive();

    newRevision = ShadowTreeRevision{
        std::move(newRootShadowNode), newRevisionNumber, telemetry};

    currentRevision_ = newRevision;
  }

  emitLayoutEvents(affectedLayoutableNodes);

  if (commitMode == CommitMode::Normal) {
    //10.shadow tree处理完成进行mount处理
    mount(std::move(newRevision), commitOptions.mountSynchronously);
  }

  return CommitStatus::Succeeded;
}
cpp 复制代码
void ShadowTree::mount(ShadowTreeRevision revision, bool mountSynchronously)
    const {
  mountingCoordinator_->push(std::move(revision));
  //11.处理mount
  delegate_.shadowTreeDidFinishTransaction(
      mountingCoordinator_, mountSynchronously);
}
cpp 复制代码
void UIManager::shadowTreeDidFinishTransaction(
    std::shared_ptr<const MountingCoordinator> mountingCoordinator,
    bool mountSynchronously) const {
  TraceSection s("UIManager::shadowTreeDidFinishTransaction");

  if (delegate_ != nullptr) {
    //13.    
    delegate_->uiManagerDidFinishTransaction(
        std::move(mountingCoordinator), mountSynchronously);
  }
}
cpp 复制代码
//14.是在Scheduler来进行的调度
void Scheduler::uiManagerDidFinishTransaction(
    std::shared_ptr<const MountingCoordinator> mountingCoordinator,
    bool mountSynchronously) {
  TraceSection s("Scheduler::uiManagerDidFinishTransaction");

  if (delegate_ != nullptr) {
    // This is no-op on all platforms except for Android where we need to
    // observe each transaction to be able to mount correctly.
    delegate_->schedulerDidFinishTransaction(mountingCoordinator);

    if (!mountSynchronously) {
      auto surfaceId = mountingCoordinator->getSurfaceId();

      runtimeScheduler_->scheduleRenderingUpdate(
          surfaceId,
          [delegate = delegate_,
           mountingCoordinator = std::move(mountingCoordinator)]() {
            delegate->schedulerShouldRenderTransactions(mountingCoordinator);
          });
    } else {
      delegate_->schedulerShouldRenderTransactions(mountingCoordinator);
    }
  }
}
cpp 复制代码
void FabricUIManagerBinding::schedulerShouldRenderTransactions(
    const std::shared_ptr<const MountingCoordinator>& mountingCoordinator) {
  auto mountingManager =
      getMountingManager("schedulerShouldRenderTransactions");
  if (!mountingManager) {
    return;
  }
  if (ReactNativeFeatureFlags::enableAccumulatedUpdatesInRawPropsAndroid()) {
    //15.调度
    auto mountingTransaction = mountingCoordinator->pullTransaction();
    if (mountingTransaction.has_value()) {
      auto transaction = std::move(*mountingTransaction);
      //17.执行真正的指令
      mountingManager->executeMount(transaction);
    }
  } else {
    std::vector<MountingTransaction> pendingTransactions;

    {
      // Retain the lock to access the pending transactions but not to execute
      // the mount operations because that method can call into this method
      // again.
      //
      // This can be re-entrant when mounting manager triggers state updates
      // synchronously (this can happen when committing from the UI thread).
      // This is safe because we're already combining all the transactions for
      // the same surface ID in a single transaction in the pending transactions
      // list, so operations won't run out of order.
      std::unique_lock<std::mutex> lock(pendingTransactionsMutex_);
      pendingTransactions_.swap(pendingTransactions);
    }

    for (auto& transaction : pendingTransactions) {
      mountingManager->executeMount(transaction);
    }
  }
}
cpp 复制代码
std::optional<MountingTransaction> MountingCoordinator::pullTransaction(
    bool willPerformAsynchronously) const {
  TraceSection section("MountingCoordinator::pullTransaction");

  std::scoped_lock lock(mutex_);

  auto transaction = std::optional<MountingTransaction>{};

  // Base case
  if (lastRevision_.has_value()) {
    number_++;

    auto telemetry = lastRevision_->telemetry;

    telemetry.willDiff();
    //16.这里是进行diff的地方,将shadowtree变成nativeview对应的实际指令
    auto mutations = calculateShadowViewMutations(
        *baseRevision_.rootShadowNode, *lastRevision_->rootShadowNode);

    telemetry.didDiff();

    transaction = MountingTransaction{
        surfaceId_, number_, std::move(mutations), telemetry};
  }
cpp 复制代码
void FabricMountingManager::executeMount(
    const MountingTransaction& transaction) {
  TraceSection section("FabricMountingManager::executeMount");

  std::scoped_lock lock(commitMutex_);
  auto finishTransactionStartTime = telemetryTimePointNow();

  auto env = jni::Environment::current();

  auto telemetry = transaction.getTelemetry();
  auto surfaceId = transaction.getSurfaceId();
  auto& mutations = transaction.getMutations();

  bool maintainMutationOrder =
      ReactNativeFeatureFlags::disableMountItemReorderingAndroid();

  auto revisionNumber = telemetry.getRevisionNumber();

  std::vector<CppMountItem> cppCommonMountItems;
  std::vector<CppMountItem> cppDeleteMountItems;
  std::vector<CppMountItem> cppUpdatePropsMountItems;
  std::vector<CppMountItem> cppUpdateStateMountItems;
  std::vector<CppMountItem> cppUpdatePaddingMountItems;
  std::vector<CppMountItem> cppUpdateLayoutMountItems;
  std::vector<CppMountItem> cppUpdateOverflowInsetMountItems;
  std::vector<CppMountItem> cppUpdateEventEmitterMountItems;

  {
    std::lock_guard allocatedViewsLock(allocatedViewsMutex_);

    auto allocatedViewsIterator = allocatedViewRegistry_.find(surfaceId);
    auto defaultAllocatedViews = std::unordered_set<Tag>{};
    // Do not remove `defaultAllocatedViews` or initialize
    // `std::unordered_set<Tag>{}` inline in below ternary expression - if falsy
    // operand is a value type, the compiler will decide the expression to be a
    // value type, an unnecessary (sometimes expensive) copy will happen as a
    // result.
    auto& allocatedViewTags =
        allocatedViewsIterator != allocatedViewRegistry_.end()
        ? allocatedViewsIterator->second
        : defaultAllocatedViews;
    if (allocatedViewsIterator == allocatedViewRegistry_.end()) {
      LOG(ERROR) << "Executing commit after surface " << surfaceId
                 << " was stopped!";
    }

    for (const auto& mutation : mutations) {
      auto parentTag = mutation.parentTag;
      const auto& oldChildShadowView = mutation.oldChildShadowView;
      const auto& newChildShadowView = mutation.newChildShadowView;
      auto& mutationType = mutation.type;
      auto& index = mutation.index;

      bool isVirtual = mutation.mutatedViewIsVirtual();
      switch (mutationType) {
        case ShadowViewMutation::Create: {
          bool shouldCreateView =
              !allocatedViewTags.contains(newChildShadowView.tag);

          if (shouldCreateView) {
            cppCommonMountItems.push_back(
                CppMountItem::CreateMountItem(newChildShadowView));
            allocatedViewTags.insert(newChildShadowView.tag);
          }
          break;
        }
        case ShadowViewMutation::Remove: {
          if (!isVirtual) {
            cppCommonMountItems.push_back(CppMountItem::RemoveMountItem(
                parentTag, oldChildShadowView, index));
          }
          break;
        }
        case ShadowViewMutation::Delete: {
          (maintainMutationOrder ? cppCommonMountItems : cppDeleteMountItems)
              .push_back(CppMountItem::DeleteMountItem(oldChildShadowView));
          if (allocatedViewTags.erase(oldChildShadowView.tag) != 1) {
            LOG(ERROR) << "Emitting delete for unallocated view "
                       << oldChildShadowView.tag;
          }
          break;
        }
        case ShadowViewMutation::Update: {
          if (!isVirtual) {
            if (!allocatedViewTags.contains(newChildShadowView.tag)) {
              LOG(ERROR) << "Emitting update for unallocated view "
                         << newChildShadowView.tag;
            }

            if (oldChildShadowView.props != newChildShadowView.props) {
              (maintainMutationOrder ? cppCommonMountItems
                                     : cppUpdatePropsMountItems)
                  .push_back(CppMountItem::UpdatePropsMountItem(
                      oldChildShadowView, newChildShadowView));
            }
            if (oldChildShadowView.state != newChildShadowView.state) {
              (maintainMutationOrder ? cppCommonMountItems
                                     : cppUpdateStateMountItems)
                  .push_back(
                      CppMountItem::UpdateStateMountItem(newChildShadowView));
            }

            // Padding: padding mountItems must be executed before layout props
            // are updated in the view. This is necessary to ensure that events
            // (resulting from layout changes) are dispatched with the correct
            // padding information.
            if (oldChildShadowView.layoutMetrics.contentInsets !=
                newChildShadowView.layoutMetrics.contentInsets) {
              (maintainMutationOrder ? cppCommonMountItems
                                     : cppUpdatePaddingMountItems)
                  .push_back(
                      CppMountItem::UpdatePaddingMountItem(newChildShadowView));
            }

            if (oldChildShadowView.layoutMetrics !=
                newChildShadowView.layoutMetrics) {
              (maintainMutationOrder ? cppCommonMountItems
                                     : cppUpdateLayoutMountItems)
                  .push_back(CppMountItem::UpdateLayoutMountItem(
                      mutation.newChildShadowView, parentTag));
            }

            // OverflowInset: This is the values indicating boundaries including
            // children of the current view. The layout of current view may not
            // change, and we separate this part from layout mount items to not
            // pack too much data there.
            if ((oldChildShadowView.layoutMetrics.overflowInset !=
                 newChildShadowView.layoutMetrics.overflowInset)) {
              (maintainMutationOrder ? cppCommonMountItems
                                     : cppUpdateOverflowInsetMountItems)
                  .push_back(CppMountItem::UpdateOverflowInsetMountItem(
                      newChildShadowView));
            }
          }

          if (oldChildShadowView.eventEmitter !=
              newChildShadowView.eventEmitter) {
            (maintainMutationOrder ? cppCommonMountItems
                                   : cppUpdatePropsMountItems)
                .push_back(CppMountItem::UpdateEventEmitterMountItem(
                    mutation.newChildShadowView));
          }
          break;
        }
        case ShadowViewMutation::Insert: {
          if (!isVirtual) {
            // Insert item
            cppCommonMountItems.push_back(CppMountItem::InsertMountItem(
                parentTag, newChildShadowView, index));

            bool shouldCreateView =
                !allocatedViewTags.contains(newChildShadowView.tag);
            if (ReactNativeFeatureFlags::
                    enableAccumulatedUpdatesInRawPropsAndroid()) {
              if (shouldCreateView) {
                LOG(ERROR) << "Emitting insert for unallocated view "
                           << newChildShadowView.tag;
              }
              (maintainMutationOrder ? cppCommonMountItems
                                     : cppUpdatePropsMountItems)
                  .push_back(CppMountItem::UpdatePropsMountItem(
                      {}, newChildShadowView));
            } else {
              if (shouldCreateView) {
                LOG(ERROR) << "Emitting insert for unallocated view "
                           << newChildShadowView.tag;
                (maintainMutationOrder ? cppCommonMountItems
                                       : cppUpdatePropsMountItems)
                    .push_back(CppMountItem::UpdatePropsMountItem(
                        {}, newChildShadowView));
              }
            }

            // State
            if (newChildShadowView.state) {
              (maintainMutationOrder ? cppCommonMountItems
                                     : cppUpdateStateMountItems)
                  .push_back(
                      CppMountItem::UpdateStateMountItem(newChildShadowView));
            }

            // Padding: padding mountItems must be executed before layout props
            // are updated in the view. This is necessary to ensure that events
            // (resulting from layout changes) are dispatched with the correct
            // padding information.
            if (newChildShadowView.layoutMetrics.contentInsets !=
                EdgeInsets::ZERO) {
              (maintainMutationOrder ? cppCommonMountItems
                                     : cppUpdatePaddingMountItems)
                  .push_back(
                      CppMountItem::UpdatePaddingMountItem(newChildShadowView));
            }

            // Layout
            (maintainMutationOrder ? cppCommonMountItems
                                   : cppUpdateLayoutMountItems)
                .push_back(CppMountItem::UpdateLayoutMountItem(
                    newChildShadowView, parentTag));

            // OverflowInset: This is the values indicating boundaries including
            // children of the current view. The layout of current view may not
            // change, and we separate this part from layout mount items to not
            // pack too much data there.
            if (newChildShadowView.layoutMetrics.overflowInset !=
                EdgeInsets::ZERO) {
              (maintainMutationOrder ? cppCommonMountItems
                                     : cppUpdateOverflowInsetMountItems)
                  .push_back(CppMountItem::UpdateOverflowInsetMountItem(
                      newChildShadowView));
            }
          }

          // EventEmitter
          // On insert we always update the event emitter, as we do not pass
          // it in when preallocating views
          (maintainMutationOrder ? cppCommonMountItems
                                 : cppUpdateEventEmitterMountItems)
              .push_back(CppMountItem::UpdateEventEmitterMountItem(
                  mutation.newChildShadowView));

          break;
        }
        default: {
          break;
        }
      }
    }
  }

  // We now have all the information we need, including ordering of mount items,
  // to know exactly how much space must be allocated
  auto [batchMountItemIntsSize, batchMountItemObjectsSize] = computeBufferSizes(
      cppCommonMountItems,
      cppDeleteMountItems,
      cppUpdatePropsMountItems,
      cppUpdateStateMountItems,
      cppUpdatePaddingMountItems,
      cppUpdateLayoutMountItems,
      cppUpdateOverflowInsetMountItems,
      cppUpdateEventEmitterMountItems);

  //19.拿到Java层的FabricUIManager.java中的scheduleMountItem方法进行调度
  static auto scheduleMountItem = JFabricUIManager::javaClassStatic()
                                      ->getMethod<void(
                                          JMountItem::javaobject,
                                          jint,
                                          jlong,
                                          jlong,
                                          jlong,
                                          jlong,
                                          jlong,
                                          jlong,
                                          jlong,
                                          jint)>("scheduleMountItem");

  if (batchMountItemIntsSize == 0) {
    auto finishTransactionEndTime = telemetryTimePointNow();
    scheduleMountItem(
        javaUIManager_,
        nullptr,
        telemetry.getRevisionNumber(),
        telemetryTimePointToMilliseconds(telemetry.getCommitStartTime()),
        telemetryTimePointToMilliseconds(telemetry.getDiffStartTime()),
        telemetryTimePointToMilliseconds(telemetry.getDiffEndTime()),
        telemetryTimePointToMilliseconds(telemetry.getLayoutStartTime()),
        telemetryTimePointToMilliseconds(telemetry.getLayoutEndTime()),
        telemetryTimePointToMilliseconds(finishTransactionStartTime),
        telemetryTimePointToMilliseconds(finishTransactionEndTime),
        telemetry.getAffectedLayoutNodesCount());
    return;
  }

  // Allocate the intBuffer and object array, now that we know exact sizes
  // necessary
  InstructionBuffer buffer = {
      env,
      env->NewIntArray(batchMountItemIntsSize),
      jni::JArrayClass<jobject>::newArray(batchMountItemObjectsSize),
  };

  // Fill in arrays
  int prevMountItemType = -1;

  // Fill in CREATE instructions.
  for (int i = 0; i < cppCommonMountItems.size(); i++) {
    const auto& mountItem = cppCommonMountItems[i];
    const auto& mountItemType = mountItem.type;

    // Get type here, and count forward how many items of this type are in a
    // row. Write preamble to any common type here.
    if (prevMountItemType != mountItemType) {
      int numSameItemTypes = 1;
      for (int j = i + 1; j < cppCommonMountItems.size() &&
           cppCommonMountItems[j].type == mountItemType;
           j++) {
        numSameItemTypes++;
      }

      writeMountItemPreamble(buffer, mountItemType, numSameItemTypes);
      prevMountItemType = mountItemType;
    }

    switch (mountItemType) {
      case CppMountItem::Type::Create:
        writeCreateMountItem(buffer, mountItem);
        break;
      case CppMountItem::Type::Delete:
        writeDeleteMountItem(buffer, mountItem);
        break;
      case CppMountItem::Type::Insert:
        writeInsertMountItem(buffer, mountItem);
        break;
      case CppMountItem::Type::Remove:
        writeRemoveMountItem(buffer, mountItem);
        break;
      case CppMountItem::Type::UpdateProps:
        writeUpdatePropsMountItem(buffer, mountItem);
        break;
      case CppMountItem::Type::UpdateState:
        writeUpdateStateMountItem(buffer, mountItem);
        break;
      case CppMountItem::Type::UpdateLayout:
        writeUpdateLayoutMountItem(buffer, mountItem);
        break;
      case CppMountItem::Type::UpdateEventEmitter:
        writeUpdateEventEmitterMountItem(buffer, mountItem);
        break;
      case CppMountItem::Type::UpdatePadding:
        writeUpdatePaddingMountItem(buffer, mountItem);
        break;
      case CppMountItem::Type::UpdateOverflowInset:
        writeUpdateOverflowInsetMountItem(buffer, mountItem);
        break;
      default:
        LOG(FATAL) << "Unexpected CppMountItem type: " << mountItemType;
    }
  }

  if (!cppUpdatePropsMountItems.empty()) {
    writeMountItemPreamble(
        buffer,
        CppMountItem::Type::UpdateProps,
        cppUpdatePropsMountItems.size());
    for (const auto& mountItem : cppUpdatePropsMountItems) {
      writeUpdatePropsMountItem(buffer, mountItem);
    }
  }
  if (!cppUpdateStateMountItems.empty()) {
    writeMountItemPreamble(
        buffer,
        CppMountItem::Type::UpdateState,
        cppUpdateStateMountItems.size());
    for (const auto& mountItem : cppUpdateStateMountItems) {
      writeUpdateStateMountItem(buffer, mountItem);
    }
  }
  if (!cppUpdatePaddingMountItems.empty()) {
    writeMountItemPreamble(
        buffer,
        CppMountItem::Type::UpdatePadding,
        cppUpdatePaddingMountItems.size());
    for (const auto& mountItem : cppUpdatePaddingMountItems) {
      writeUpdatePaddingMountItem(buffer, mountItem);
    }
  }
  if (!cppUpdateLayoutMountItems.empty()) {
    writeMountItemPreamble(
        buffer,
        CppMountItem::Type::UpdateLayout,
        cppUpdateLayoutMountItems.size());
    for (const auto& mountItem : cppUpdateLayoutMountItems) {
      writeUpdateLayoutMountItem(buffer, mountItem);
    }
  }
  if (!cppUpdateOverflowInsetMountItems.empty()) {
    writeMountItemPreamble(
        buffer,
        CppMountItem::Type::UpdateOverflowInset,
        cppUpdateOverflowInsetMountItems.size());
    for (const auto& mountItem : cppUpdateOverflowInsetMountItems) {
      writeUpdateOverflowInsetMountItem(buffer, mountItem);
    }
  }
  if (!cppUpdateEventEmitterMountItems.empty()) {
    writeMountItemPreamble(
        buffer,
        CppMountItem::Type::UpdateEventEmitter,
        cppUpdateEventEmitterMountItems.size());
    for (const auto& mountItem : cppUpdateEventEmitterMountItems) {
      writeUpdateEventEmitterMountItem(buffer, mountItem);
    }
  }

  // Write deletes last - so that all prop updates, etc, for the tag in the same
  // batch don't fail. Without additional machinery, moving deletes here
  // requires that the differ never produces "DELETE...CREATE" in that order for
  // the same tag. It's nice to be able to batch all similar operations together
  // for space efficiency.
  // FIXME: this optimization is incorrect when multiple transactions are
  // merged together
  if (!cppDeleteMountItems.empty()) {
    writeMountItemPreamble(
        buffer, CppMountItem::Type::Delete, cppDeleteMountItems.size());
    for (const auto& mountItem : cppDeleteMountItems) {
      writeDeleteMountItem(buffer, mountItem);
    }
  }

  static auto createMountItemsIntBufferBatchContainer =
      JFabricUIManager::javaClassStatic()
          ->getMethod<jni::alias_ref<JMountItem>(
              jint, jintArray, jni::jtypeArray<jobject>, jint)>(
              "createIntBufferBatchMountItem");
  auto batch = createMountItemsIntBufferBatchContainer(
      javaUIManager_,
      surfaceId,
      // If there are no items, we pass a nullptr instead of passing the
      // object through the JNI
      batchMountItemIntsSize > 0 ? buffer.ints : nullptr,
      batchMountItemObjectsSize > 0 ? buffer.objects.get() : nullptr,
      revisionNumber);

  auto finishTransactionEndTime = telemetryTimePointNow();

  scheduleMountItem(
      javaUIManager_,
      batch.get(),
      telemetry.getRevisionNumber(),
      telemetryTimePointToMilliseconds(telemetry.getCommitStartTime()),
      telemetryTimePointToMilliseconds(telemetry.getDiffStartTime()),
      telemetryTimePointToMilliseconds(telemetry.getDiffEndTime()),
      telemetryTimePointToMilliseconds(telemetry.getLayoutStartTime()),
      telemetryTimePointToMilliseconds(telemetry.getLayoutEndTime()),
      telemetryTimePointToMilliseconds(finishTransactionStartTime),
      telemetryTimePointToMilliseconds(finishTransactionEndTime),
      telemetry.getAffectedLayoutNodesCount());

  env->DeleteLocalRef(buffer.ints);
}
cpp 复制代码
@Override
  public void execute(MountingManager mountingManager) {
    SurfaceMountingManager surfaceMountingManager = mountingManager.getSurfaceManager(mSurfaceId);
    if (surfaceMountingManager == null) {
      FLog.e(
          TAG,
          "Skipping batch of MountItems; no SurfaceMountingManager found for [%d].",
          mSurfaceId);
      return;
    }
    if (surfaceMountingManager.isStopped()) {
      FLog.e(TAG, "Skipping batch of MountItems; was stopped [%d].", mSurfaceId);
      return;
    }
    if (ReactNativeFeatureFlags.enableFabricLogs()) {
      FLog.d(TAG, "Executing IntBufferBatchMountItem on surface [%d]", mSurfaceId);
    }

    beginMarkers("mountViews");
    int i = 0, j = 0;
    while (i < mIntBufferLen) {
      int rawType = mIntBuffer[i++];
      int type = rawType & ~INSTRUCTION_FLAG_MULTIPLE;
      int numInstructions = ((rawType & INSTRUCTION_FLAG_MULTIPLE) != 0 ? mIntBuffer[i++] : 1);

      String[] args = {"numInstructions", String.valueOf(numInstructions)};

      Systrace.beginSection(
          Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,
          "IntBufferBatchMountItem::mountInstructions::" + nameForInstructionString(type),
          args,
          args.length);
      for (int k = 0; k < numInstructions; k++) {
        if (type == INSTRUCTION_CREATE) {
          String componentName = getFabricComponentName((String) mObjBuffer[j++]);
          //20.这里也就是创建指令真正执行的地方了
          surfaceMountingManager.createView(
              componentName,
              mIntBuffer[i++],
              (ReadableMap) mObjBuffer[j++],
              (StateWrapper) mObjBuffer[j++],
              (EventEmitterWrapper) mObjBuffer[j++],
              mIntBuffer[i++] == 1);
        } else if (type == INSTRUCTION_DELETE) {
          surfaceMountingManager.deleteView(mIntBuffer[i++]);
        } else if (type == INSTRUCTION_INSERT) {
          int tag = mIntBuffer[i++];
          int parentTag = mIntBuffer[i++];
          surfaceMountingManager.addViewAt(parentTag, tag, mIntBuffer[i++]);
        } else if (type == INSTRUCTION_REMOVE) {
          surfaceMountingManager.removeViewAt(mIntBuffer[i++], mIntBuffer[i++], mIntBuffer[i++]);
        } else if (type == INSTRUCTION_UPDATE_PROPS) {
          surfaceMountingManager.updateProps(mIntBuffer[i++], (ReadableMap) mObjBuffer[j++]);
        } else if (type == INSTRUCTION_UPDATE_STATE) {
          surfaceMountingManager.updateState(mIntBuffer[i++], (StateWrapper) mObjBuffer[j++]);
        } else if (type == INSTRUCTION_UPDATE_LAYOUT) {
          int reactTag = mIntBuffer[i++];
          int parentTag = mIntBuffer[i++];
          int x = mIntBuffer[i++];
          int y = mIntBuffer[i++];
          int width = mIntBuffer[i++];
          int height = mIntBuffer[i++];
          int displayType = mIntBuffer[i++];
          int layoutDirection = mIntBuffer[i++];
          surfaceMountingManager.updateLayout(
              reactTag, parentTag, x, y, width, height, displayType, layoutDirection);
        } else if (type == INSTRUCTION_UPDATE_PADDING) {
          surfaceMountingManager.updatePadding(
              mIntBuffer[i++], mIntBuffer[i++], mIntBuffer[i++], mIntBuffer[i++], mIntBuffer[i++]);
        } else if (type == INSTRUCTION_UPDATE_OVERFLOW_INSET) {
          int reactTag = mIntBuffer[i++];
          int overflowInsetLeft = mIntBuffer[i++];
          int overflowInsetTop = mIntBuffer[i++];
          int overflowInsetRight = mIntBuffer[i++];
          int overflowInsetBottom = mIntBuffer[i++];

          surfaceMountingManager.updateOverflowInset(
              reactTag,
              overflowInsetLeft,
              overflowInsetTop,
              overflowInsetRight,
              overflowInsetBottom);
        } else if (type == INSTRUCTION_UPDATE_EVENT_EMITTER) {
          surfaceMountingManager.updateEventEmitter(
              mIntBuffer[i++], (EventEmitterWrapper) mObjBuffer[j++]);
        } else {
          throw new IllegalArgumentException(
              "Invalid type argument to IntBufferBatchMountItem: " + type + " at index: " + i);
        }
      }
      Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
    }
    endMarkers();
  }

六、总结

以上就是整体新老架构的不同,新架构提供了TurboModule,Fabric渲染,Codegen代码生成来解决旧架构中的不同问题,再来回顾下吧:

对比项 新架构 旧架构
TurboModule 提供TurboModule,将异步调用变为同步调用,提升性能和开发效率。 旧架构无TurboModule,依赖传统模块系统。
Fabric渲染 使用Fabric c++统一渲染逻辑,不在端侧渲染处理,优化渲染性能和内存占用。 旧架构依赖React Native原生渲染。
Codegen代码生成 引入Codegen工具,自动化代码生成,减少冗余。 旧架构依赖手动编写或传统代码生成工具。
相关推荐
再学一点就睡33 分钟前
深入理解 Redux:从手写核心到现代实践(附 RTK 衔接)
前端·redux
天天进步20152 小时前
从零到一:现代化充电桩App的React前端参考
前端·react.js·前端框架
柯南二号2 小时前
【大前端】React Native Flex 布局详解
前端·react native·react.js
雨白2 小时前
Android 自定义 View:属性动画和硬件加速
android
龙在天2 小时前
npm run dev 做了什么❓小白也能看懂
前端
真西西3 小时前
Koin:Kotlin轻量级依赖注入框架
android·kotlin
li理3 小时前
鸿蒙应用开发完全指南:深度解析UIAbility、页面与导航的生命周期
前端·harmonyos
去伪存真4 小时前
因为rolldown-vite比vite打包速度快, 所以必须把rolldown-vite在项目中用起来🤺
前端
KubeSphere4 小时前
Kubernetes v1.34 重磅发布:调度更快,安全更强,AI 资源管理全面进化
前端