当前位置: 首页 > news >正文

React19源码系列之 Diff算法

在之前文章中root.render执行的过程,beginWork函数是渲染过程的核心,其针对不同类型的fiber进行不同的更新处理,在FunctionComponent(函数组件)中,会针对新旧fiber进行对比处理生成新fiber。因此此次就详细记录一下新旧节点对比生成新fiber的过程,即diff 的过程。


其实react的 diff 方法无法是首次渲染还是更新的情况下都是调用 reconcileChildFibersImpl函数。

reconcileChildren

reconcileChildren 函数是 React 协调过程中的核心函数之一,主要用于协调新旧 Fiber 节点的子节点。在 React 的渲染流程中,当一个 Fiber 节点需要更新其子节点时,该函数会根据是否存在 旧的 Fiber 节点(current),选择不同的方式来处理子节点的更新,最终将处理后的子 Fiber 节点挂载到 workInProgress 节点上。

function reconcileChildren(current: Fiber | null,// 表示旧的 Fiber 节点。workInProgress: Fiber,// 表示当前正在处理的新 Fiber 节点nextChildren: any,// 表示新的子元素集合,通常是组件返回的 JSX 元素或子组件。renderLanes: Lanes,// 渲染的优先级车道。
) {if (current === null) {workInProgress.child = mountChildFibers(workInProgress,null,nextChildren,renderLanes,);} else {workInProgress.child = reconcileChildFibers(workInProgress,current.child,nextChildren,renderLanes,);}
}

mountChildFibers函数和 reconcileChildFibers 函数都有调用高阶函数 createChildReconciler 返回的一个函数。

const mountChildFibers: ChildReconciler = createChildReconciler(false);
const reconcileChildFibers: ChildReconciler = createChildReconciler(true);

createChildReconciler

createChildReconciler 函数是一个高阶函数,其主要作用是创建并返回一个用于协调子 Fiber 节点的函数 reconcileChildFibers。

function createChildReconciler(// shouldTrackSideEffects首次渲染为false,更新为trueshouldTrackSideEffects: boolean,
): ChildReconciler {//。。。// function reconcileChildFibers(){}return reconcileChildFibers;
}


reconcileChildFibers

reconcileChildFibers 函数主要用于对比新旧子节点,生成新的 Fiber 节点树,以此实现 React 组件树的更新。主要实现是调用内部的 reconcileChildFibersImpl 函数完成调和操作,最终返回 新的第一个子 Fiber 节点。

函数参数含义:

  • returnFiber,父 Fiber 节点。
  • currentFirstChild,当前的子 Fiber 节点。
  • newChild,新的子节点。
  • lanes,渲染优先级。
    function reconcileChildFibers(returnFiber: Fiber,// 父节点fibercurrentFirstChild: Fiber | null,//当前父 Fiber 节点的第一个子 Fiber 节点,如果没有子节点则为 null。newChild: any,// 新的节点lanes: Lanes,// 渲染优先级
    ): Fiber | null {try {// 根据新旧子节点的差异生成新的 Fiber 节点树,并返回第一个子 Fiber 节点。const firstChildFiber = reconcileChildFibersImpl(returnFiber,currentFirstChild,newChild,lanes,);return firstChildFiber;}catch{}
    }

    reconcileChildFibersImpl

    根据新子节点的类型(如 React 元素、数组、可迭代对象、Promise 等),调用相应的调和函数来生成新的子 Fiber 节点,并返回第一个子 Fiber 节点或null。

    function reconcileChildFibersImpl(returnFiber: Fiber,// 当前正在处理的父 Fiber 节点。currentFirstChild: Fiber | null,// 当前父 Fiber 节点的第一个子 Fiber 节点,如果没有子节点则为 null。newChild: any,//新的子节点信息,可以是不同类型的数据,如 React 元素、数组、可迭代对象等。lanes: Lanes,// 渲染优先级车道
    ): Fiber | null {// 判断新子节点是否为无 key 的顶级 Fragment 组件类型,如果是,则将新子节点更新为其 props.children,因为 Fragment 本身只是一个占位符,实际的子节点内容在其 props.children 中。const isUnkeyedTopLevelFragment =typeof newChild === 'object' &&newChild !== null &&newChild.type === REACT_FRAGMENT_TYPE &&newChild.key === null;// fragment  占位组件,将其child设置为newChildif (isUnkeyedTopLevelFragment) {// validateFragmentProps(newChild, null, returnFiber);newChild = newChild.props.children;}// Handle object types// 处理对象类型的子节点if (typeof newChild === 'object' && newChild !== null) {switch (newChild.$$typeof) {// 根据 $$typeof 判断 React 元素类型case REACT_ELEMENT_TYPE: {// const prevDebugInfo = pushDebugInfo(newChild._debugInfo);const firstChild = placeSingleChild(reconcileSingleElement(returnFiber,currentFirstChild,newChild,lanes,),);// currentDebugInfo = prevDebugInfo;return firstChild;}// 处理 React Portal 类型case REACT_PORTAL_TYPE:return placeSingleChild(reconcileSinglePortal(returnFiber,currentFirstChild,newChild,lanes,),);// 处理 React Lazy 类型case REACT_LAZY_TYPE: {// const prevDebugInfo = pushDebugInfo(newChild._debugInfo);let result;// newChild._payload 是传递给初始化函数的数据const payload = newChild._payload;// newChild._init 是懒加载组件的初始化函数。const init = newChild._init;// 调用初始化函数 init 并传入 payload,以获取实际的组件。通常,init 函数会动态导入组件并返回。result = init(payload);// reconcileChildFibersImpl:这是一个内部函数,用于调和子 Fiber 节点。它会比较新旧 Fiber 树,找出差异并更新 Fiber 树。const firstChild = reconcileChildFibersImpl(returnFiber,currentFirstChild,result,lanes,);// currentDebugInfo = prevDebugInfo;return firstChild;}}// 处理数组类型的子节点if (isArray(newChild)) {// const prevDebugInfo = pushDebugInfo(newChild._debugInfo);const firstChild = reconcileChildrenArray(returnFiber,currentFirstChild,newChild,lanes,);// currentDebugInfo = prevDebugInfo;return firstChild;}// 处理可迭代类型的子节点if (getIteratorFn(newChild)) {// const prevDebugInfo = pushDebugInfo(newChild._debugInfo);const firstChild = reconcileChildrenIteratable(returnFiber,currentFirstChild,newChild,lanes,);// currentDebugInfo = prevDebugInfo;return firstChild;}// 处理异步可迭代类型的子节点if (enableAsyncIterableChildren &&typeof newChild[ASYNC_ITERATOR] === 'function') {// const prevDebugInfo = pushDebugInfo(newChild._debugInfo);const firstChild = reconcileChildrenAsyncIteratable(returnFiber,currentFirstChild,newChild,lanes,);// currentDebugInfo = prevDebugInfo;return firstChild;}// 处理 Promise 类型的子节点if (typeof newChild.then === 'function') {const thenable: Thenable<any> = (newChild: any);// const prevDebugInfo = pushDebugInfo((thenable: any)._debugInfo);const firstChild = reconcileChildFibersImpl(returnFiber,currentFirstChild,unwrapThenable(thenable),lanes,);// currentDebugInfo = prevDebugInfo;return firstChild;}// 处理 React Context 类型if (newChild.$$typeof === REACT_CONTEXT_TYPE) {const context: ReactContext<mixed> = (newChild: any);return reconcileChildFibersImpl(returnFiber,currentFirstChild,readContextDuringReconciliation(returnFiber, context, lanes),lanes,);}// throwOnInvalidObjectType(returnFiber, newChild);}// 处理字符串、数字和大整数类型的子节点if ((typeof newChild === 'string' && newChild !== '') ||typeof newChild === 'number' ||typeof newChild === 'bigint') {return placeSingleChild(reconcileSingleTextNode(returnFiber,currentFirstChild,// $FlowFixMe[unsafe-addition] Flow doesn't want us to use `+` operator with string and bigint'' + newChild,lanes,),);}// Remaining cases are all treated as empty.// 对于其他未处理的情况,将其视为空节点,调用 deleteRemainingChildren 函数删除当前父节点的所有剩余子节点,并返回 null。return deleteRemainingChildren(returnFiber, currentFirstChild);}

    情况1:新节点是object类型且不为null

    1-1 检查newChild.$$typeof为REACT_ELEMENT_TYPE

    case REACT_ELEMENT_TYPE: {
    // const prevDebugInfo = pushDebugInfo(newChild._debugInfo);const firstChild = placeSingleChild(reconcileSingleElement(returnFiber,currentFirstChild,newChild,lanes,),);// currentDebugInfo = prevDebugInfo;return firstChild;
    }


    reconcileSingleElement

    reconcileSingleElement 函数主要是将一个新的 React 元素与现有的子 Fiber 节点进行比较,根据比较结果决定是复用现有的 Fiber 节点,还是创建一个新的 Fiber 节点。

    处理步骤:

    1、while循环遍历fiber的子节点,下一个处理的节点是fiber.sibling。
    2、检查新旧fiber的key 。

    • key相同:    
      • 如果是fragment,删除当前子 Fiber 节点之后的所有兄弟节点,复用其子节点,返回。   
      • 如果是lazy:删除当前子 Fiber 节点之后的所有兄弟节点,复用,处理ref,返回。   
      • 其他:删除当前子 Fiber 节点及其之后的所有兄弟节点,然后跳出循环。
    • key不同:删除当前子 Fiber 节点及其之后的所有兄弟节点,然后跳出循环。

    3、若新元素是 Fragment 类型,调用 createFiberFromFragment 函数创建新的 Fiber 节点,设置其 return 属性指向父 Fiber 节点,最后返回该节点。
    4、若不是 Fragment 类型,调用 createFiberFromElement 函数创建新的 Fiber 节点,处理 ref,设置其 return 属性指向父 Fiber 节点,最后返回该节点。

    function reconcileSingleElement(returnFiber: Fiber,// 当前元素的父 Fiber 节点。currentFirstChild: Fiber | null,// 当前的第一个子 Fiber 节点,如果没有则为 null。element: ReactElement,// 要调和的 React 元素。即新元素lanes: Lanes,// 渲染优先级车道。
    ): Fiber {//  React 元素的 key 属性,key 用于帮助 React 识别哪些元素发生了变化,提高调和效率。const key = element.key;// 用于遍历当前的子 Fiber 节点。let child = currentFirstChild;while (child !== null) {// the first item in the list.// 当前子 Fiber 节点的 key 与新元素的 key 相同,继续检查元素类型。if (child.key === key) {const elementType = element.type;// 如果新元素是fragment类型if (elementType === REACT_FRAGMENT_TYPE) {if (child.tag === Fragment) {// 省略代码,看后续代码片段return existing;}} else {// 懒加载组件if (child.elementType === elementType  ||(typeof elementType === 'object' &&elementType !== null &&elementType.$$typeof === REACT_LAZY_TYPE &&resolveLazy(elementType) === child.type)) {// 省略代码,看代码片段return existing;}}// Didn't match.deleteRemainingChildren(returnFiber, child);// 跳出循环break;} else {// key 不匹配,标记删除deleteChild(returnFiber, child);}//移动到下一个子 Fiber 节点child = child.sibling;}if (element.type === REACT_FRAGMENT_TYPE) {// 创建新的 Fiber 节点const created = createFiberFromFragment(element.props.children,returnFiber.mode,lanes,element.key,);created.return = returnFiber;// validateFragmentProps(element, created, returnFiber);return created;} else {// 创建新的 Fiber 节点const created = createFiberFromElement(element, returnFiber.mode, lanes);coerceRef(created, element);created.return = returnFiber;return created;}
    }

     代码片段:

    if (child.tag === Fragment) {// 标记要删除child的所有兄弟节点deleteRemainingChildren(returnFiber, child.sibling);// 复用fragment下的子节点const existing = useFiber(child, element.props.children);//设置其return属性即父节点existing.return = returnFiber;// validateFragmentProps(element, existing, returnFiber);return existing;
    }

    为什么child.tag = Fragment,要删除 child 的所有兄弟节点?

    Fragment 是 React 里用于将多个子元素分组但又不引入额外 DOM 节点的一种方式。它允许你在不添加多余父元素的情况下返回多个元素。

    从结构层面来看,Fragment 可以当作一个逻辑上的容器,它本身不会在 DOM 树中产生额外节点。所以在 Fiber 树里,Fragment 节点期望能直接包含其子元素,而不应该有其他兄弟节点与其并列。

    Fiber 调和过程的目的是找出新旧 Fiber 树之间的差异,然后最小化 DOM 操作来更新页面。当遇到 Fragment 节点时,React 会认为 Fragment 应该是当前层级下的唯一逻辑容器。如果 Fragment 有兄弟节点,可能会打乱这种逻辑结构,使得调和过程变得复杂。

    代码片段: 

    if (// 检查当前 child 节点的 elementType 是否与新元素的 elementType 相同。elementType 通常表示元素的类型,比如函数组件、类组件或者 HTML 标签名等。如果相同,说明可能可以复用这个节点。child.elementType === elementType  ||// 懒加载组件(typeof elementType === 'object' &&elementType !== null &&elementType.$$typeof === REACT_LAZY_TYPE &&resolveLazy(elementType) === child.type)) {// 标记删除所有的兄弟节点deleteRemainingChildren(returnFiber, child.sibling);// 复用child节点const existing = useFiber(child, element.props);// 处理refcoerceRef(existing, element);existing.return = returnFiber;return existing;
    }

    createFiberFromElement

    createFiberFromElement 函数的主要功能是依据传入的 React 元素(ReactElement)创建一个对应的 Fiber 节点。

    函数参数说明:

    • element: ReactElement:待转换的 React 元素,它包含了组件的类型、属性、key 等信息。
    • mode: TypeOfMode:节点的模式,用于控制该节点及其子节点的行为,像是否启用并发模式等。
    • lanes: Lanes:渲染优先级车道,用来确定该节点的渲染优先级。
       function createFiberFromElement(element: ReactElement,mode: TypeOfMode,lanes: Lanes,
      ): Fiber {// 初始ownerlet owner = null;// 获取 React 元素的类型,可能是函数组件、类组件或者原生 DOM 元素类型。const type = element.type;// 获取 React 元素的 key 属性,key 用于辅助 React 识别哪些元素发生了变化,提升调和效率。const key = element.key;// 获取 React 元素的属性,也就是传递给组件的新属性。const pendingProps = element.props;const fiber = createFiberFromTypeAndProps(type,// 元素类型key,pendingProps,owner,mode,// 模式,并发模式lanes,// 渲染优先级车道);return fiber;
      }

      createFiberFromTypeAndProps

      createFiberFromTypeAndProps 函数的主要功能是根据传入的组件类型、属性等信息,创建相应类型的 Fiber 节点。在 React 的 Fiber 架构中,Fiber 节点是协调和渲染过程的核心数据结构,该函数会根据不同的组件类型(如函数组件、类组件、各种特殊组件等)设置 Fiber 节点的属性和类型标签,最终返回创建好的 Fiber 节点,为后续的渲染和更新操作提供基础。

      函数参数说明

      • type: any:React 组件的类型,可以是函数、类、字符串(代表原生 DOM 元素)或特殊的 React 类型(如 FragmentContext 等)。
      • key: null | string:节点的 key 属性,用于帮助 React 识别哪些元素发生了变化,提高调和效率。
      • pendingProps: any:组件的待处理属性。
      • owner: null | ReactComponentInfo | Fiber:创建该组件的所有者,可能是 nullReactComponentInfoFiber 节点。
      • mode: TypeOfMode:节点的模式,用于控制该节点及其子节点的行为,例如是否启用并发模式等。
      • lanes: Lanes:渲染优先级车道,用于确定该节点的渲染优先级。
       function createFiberFromTypeAndProps(type: any, // React$ElementTypekey: null | string,pendingProps: any,owner: null | ReactComponentInfo | Fiber,mode: TypeOfMode,lanes: Lanes,
      ): Fiber {// fiberTag 初始化为 FunctionComponent,表示默认情况下将组件视为函数组件。// fiberTag代表节点类型let fiberTag = FunctionComponent;// 存储组件类型let resolvedType = type;if (typeof type === 'function') {// 如果 type 是函数类型,调用 shouldConstruct 函数判断该函数是否为类组件的构造函数。如果是,则将 fiberTag 设置为 ClassComponent。if (shouldConstruct(type)) {fiberTag = ClassComponent;} } else if (typeof type === 'string') {// 省略代码。。。看后面的代码片段分析} else {// 创建不同类型的fiber节点getTag: switch (type) {// 当 type 为 REACT_FRAGMENT_TYPE 时,表示当前元素是一个 Fragment。Fragment 是 React 中用于分组多个子元素而不引入额外 DOM 节点的方式。case REACT_FRAGMENT_TYPE:return createFiberFromFragment(pendingProps.children, mode, lanes, key);// 当 type 为 REACT_STRICT_MODE_TYPE 时,表示当前元素是一个 StrictMode 组件。StrictMode 用于在开发模式下帮助发现潜在的问题,如不安全的生命周期方法、过时的 API 使用等。case REACT_STRICT_MODE_TYPE:fiberTag = Mode;mode |= StrictLegacyMode;if (disableLegacyMode || (mode & ConcurrentMode) !== NoMode) {// Strict effects should never run on legacy rootsmode |= StrictEffectsMode;if (enableDO_NOT_USE_disableStrictPassiveEffect &&pendingProps.DO_NOT_USE_disableStrictPassiveEffect) {mode |= NoStrictPassiveEffectsMode;}}break;// 当 type 为 REACT_PROFILER_TYPE 时,表示当前元素是一个 Profiler 组件。Profiler 用于测量 React 应用的性能,记录组件渲染的时间。case REACT_PROFILER_TYPE:return createFiberFromProfiler(pendingProps, mode, lanes, key);// :当 type 为 REACT_SUSPENSE_TYPE 时,表示当前元素是一个 Suspense 组件。Suspense 用于处理异步加载的组件,在组件加载完成之前显示一个加载指示器。case REACT_SUSPENSE_TYPE:return createFiberFromSuspense(pendingProps, mode, lanes, key);// 省略一些代码。。// Fall throughdefault: {if (typeof type === 'object' && type !== null) {switch (type.$$typeof) {// 当 type.$$typeof 为 REACT_PROVIDER_TYPE 时,表明这是一个 Context.Provider 组件。case REACT_PROVIDER_TYPE:if (!enableRenderableContext) {fiberTag = ContextProvider;break getTag;}// Fall through// 当 type.$$typeof 为 REACT_CONTEXT_TYPE 时,代表这是一个 Context 对象。      case REACT_CONTEXT_TYPE:if (enableRenderableContext) {fiberTag = ContextProvider;break getTag;} else {fiberTag = ContextConsumer;break getTag;}
      // 当 type.$$typeof 为 REACT_CONSUMER_TYPE 时,说明这是一个 Context.Consumer 组件。case REACT_CONSUMER_TYPE:if (enableRenderableContext) {fiberTag = ContextConsumer;break getTag;}// Fall through
      // 当 type.$$typeof 为 REACT_FORWARD_REF_TYPE 时,表明这是一个使用 React.forwardRef 创建的组件。case REACT_FORWARD_REF_TYPE:fiberTag = ForwardRef;break getTag;// 当 type.$$typeof 为 REACT_MEMO_TYPE 时,意味着这是一个使用 React.memo 包装的组件。            case REACT_MEMO_TYPE:fiberTag = MemoComponent;break getTag;// 当 type.$$typeof 为 REACT_LAZY_TYPE 时,表示这是一个使用 React.lazy 创建的懒加载组件。case REACT_LAZY_TYPE:fiberTag = LazyComponent;resolvedType = null;break getTag;}}let info = '';let typeString;typeString = type === null ? 'null' : typeof type;// 如果以上都不是,fiberTag表示错误组件fiberTag = Throw;pendingProps = new Error('Element type is invalid: expected a string (for built-in ' +'components) or a class/function (for composite components) ' +`but got: ${typeString}.${info}`,);resolvedType = null;}}}// 创建fiberconst fiber = createFiber(fiberTag, pendingProps, key, mode);fiber.elementType = type;fiber.type = resolvedType;fiber.lanes = lanes;return fiber;
      }

      可以看出组件lazy、memo、forwardRef、Provide、Consumer组件都是使用createFiber创建相应的fiber节点。

      代码片段:

      if (typeof type === 'string') {if (supportsResources && supportsSingletons) {// 获取宿主环境的上下文信息,这可能包含了一些与渲染环境相关的数据。const hostContext = getHostContext();// isHostHoistableType函数判断该元素是否为可提升的宿主类型fiberTag = isHostHoistableType(type, pendingProps, hostContext)? HostHoistable// meta,title等: isHostSingletonType(type)? HostSingleton : HostComponent;} else if (supportsResources) {const hostContext = getHostContext();fiberTag = isHostHoistableType(type, pendingProps, hostContext)? HostHoistable: HostComponent;} else if (supportsSingletons) {fiberTag = isHostSingletonType(type) ? HostSingleton : HostComponent;} else {fiberTag = HostComponent;}
      }

      例子:createContext的使用(Provider 和 Consumer)

      import { createContext } from 'react';const ThemeContext = createContext('light');function App() {const [theme, setTheme] = useState('light');// ...return (<ThemeContext.Provider value={theme}><Page /></ThemeContext.Provider>);
      }
      function Button() {// 🟡 Legacy way (not recommended)return (<ThemeContext.Consumer>{theme => (<button className={theme} />)}</ThemeContext.Consumer>);
      }

       createFiberFromFragment

      createFiberFromFragment 函数用于创建一个表示 React Fragment 的 Fiber 节点。它通过调用 createFiber 函数初始化基本的 Fiber 结构,并设置其 lanes 属性以标记该 Fiber 的优先级。Fragment 是一种特殊的 React 元素,用于将多个子元素分组而不引入额外的 DOM 节点。

      函数参数说明:

      • Fragment:指定 Fiber 类型为 Fragment(对应 React 内部的 Fragment 标签类型)。
      • elements:Fragment 包含的子元素集合,通常是一个数组。
      • key:Fragment 的 key 值,用于在协调过程中识别元素。
      • mode:Fiber 的模式,决定了渲染行为(如并发模式、严格模式等)。
      function createFiberFromFragment(elements: ReactFragment,mode: TypeOfMode,lanes: Lanes,key: null | string,
      ): Fiber {
      // Fragment常量 为7const fiber = createFiber(Fragment, elements, key, mode);fiber.lanes = lanes;return fiber;
      }

      createFiberFromSuspense

      createFiberFromSuspense 函数用于创建一个表示 React Suspense 组件的 Fiber 节点。Suspense 是 React 中用于处理异步加载内容的特性,允许组件在等待数据时显示加载状态。该函数初始化了 Suspense 组件的基本 Fiber 结构,并设置了相关属性。

      参数说明:

      • SuspenseComponent:指定 Fiber 类型为 Suspense 组件(对应 React 内部的 Suspense 标签类型)。
      • pendingProps:Suspense 组件的属性,通常包含 fallback(加载状态内容)和子组件。
      • key:Suspense 组件的 key 值,用于在协调过程中识别元素。
      • mode:Fiber 的模式,决定了渲染行为(如并发模式、严格模式等)。
      function createFiberFromSuspense(pendingProps: any,mode: TypeOfMode,lanes: Lanes,key: null | string,
      ): Fiber {const fiber = createFiber(SuspenseComponent, pendingProps, key, mode);fiber.elementType = REACT_SUSPENSE_TYPE;fiber.lanes = lanes;return fiber;
      }

      1-2 检查newChild.$$typeof为REACT_PORTAL_TYPE

      1. 遍历现有的子 Fiber 节点。
      2. 检查新旧节点的key是否相同。
        1. key相同:
          1. 可复用:删除当前子 Fiber 节点之后的所有兄弟节点。复用当前子 Fiber 节点,并更新其 children 属性。复用节点的 return 属性指向父 Fiber 节点,返回复用节点。
          2. 不可复用:删除当前子 Fiber 节点之后的所有兄弟节点,并跳出循环。
        2. key不同:删除当前子 Fiber 节点之后的所有兄弟节点。
      3. 结束循环。
      4. 创建新的 Fiber 节点并返回。
         // 处理 React Portal 类型case REACT_PORTAL_TYPE:return placeSingleChild(reconcileSinglePortal(returnFiber,currentFirstChild,newChild,lanes,),);

      reconcileSinglePortal

      reconcileSinglePortal 函数的主要作用是调和单个 ReactPortal 元素。在 React 中,Portal 是一种将子节点渲染到 DOM 树中当前组件层次结构之外位置的方式。该函数会尝试复用现有的 Fiber 节点,如果无法复用则创建一个新的 Fiber 节点,同时处理相关的兄弟节点删除操作。

      处理过程:

      1、遍历现有的子 Fiber 节点

      2、检查新旧节点的key是否相同

      • key相同:
        • 可复用:删除当前子 Fiber 节点之后的所有兄弟节点。复用当前子 Fiber 节点,并更新其 children 属性。复用节点的 return 属性指向父 Fiber 节点。返回复用节点
        • 不可复用:删除当前子 Fiber 节点之后的所有兄弟节点,并跳出循环。
      • key不同:删除当前子 Fiber 节点之后的所有兄弟节点。

      2、结束循环。

      3、创建新的 Fiber 节点,并返回

      function reconcileSinglePortal(returnFiber: Fiber,//:父 Fiber 节点,即当前 Portal 元素所属的父节点。currentFirstChild: Fiber | null,// 当前父节点的第一个子 Fiber 节点,可能为 null。portal: ReactPortal,// 新的 ReactPortal 元素,包含了要渲染的子节点以及目标容器信息。lanes: Lanes,// 渲染优先级车道,用于表示当前操作的优先级。
      ): Fiber {const key = portal.key;let child = currentFirstChild;while (child !== null) {if (child.key === key) {if (child.tag === HostPortal &&// 检查子节点的目标容器信息是否与 Portal 元素的目标容器信息相同。child.stateNode.containerInfo === portal.containerInfo &&// 检查子节点的实现方式是否与 Portal 元素的实现方式相同。child.stateNode.implementation === portal.implementation) {deleteRemainingChildren(returnFiber, child.sibling);const existing = useFiber(child, portal.children || []);existing.return = returnFiber;return existing;} else {deleteRemainingChildren(returnFiber, child);break;}} else {deleteChild(returnFiber, child);}// 将 child 指针指向当前子节点的下一个兄弟节点,继续遍历。child = child.sibling;}const created = createFiberFromPortal(portal, returnFiber.mode, lanes);created.return = returnFiber;return created;
      }

      createFiberFromPortal

      createFiberFromPortal 函数的主要功能是依据给定的 ReactPortal 对象、模式和优先级车道,创建一个 HostPortal 类型的 Fiber 节点。ReactPortal 是 React 提供的一种特殊机制,它能让子组件渲染到 DOM 树中当前组件层次结构之外的位置。此函数会为 Portal 创建对应的 Fiber 节点,以便在 Fiber 架构里对其进行调和与渲染。

      function createFiberFromPortal(portal: ReactPortal,mode: TypeOfMode,lanes: Lanes,
      ): Fiber {const pendingProps = portal.children !== null ? portal.children : [];const fiber = createFiber(HostPortal, pendingProps, portal.key, mode);fiber.lanes = lanes;fiber.stateNode = {containerInfo: portal.containerInfo,pendingChildren: null, // Used by persistent updatesimplementation: portal.implementation,};return fiber;
      }
      

      1-3 检查newChild.$$typeof为REACT_LAZY_TYPE

        // 处理 React Lazy 类型case REACT_LAZY_TYPE: {// const prevDebugInfo = pushDebugInfo(newChild._debugInfo);let result;// newChild._payload 是传递给初始化函数的数据const payload = newChild._payload;// newChild._init 是懒加载组件的初始化函数。const init = newChild._init;// 调用初始化函数 init 并传入 payload,以获取实际的组件。通常,init 函数会动态导入组件并返回。result = init(payload);// reconcileChildFibersImpl:这是一个内部函数,用于调和子 Fiber 节点。它会比较新旧 Fiber 树,找出差异并更新 Fiber 树。const firstChild = reconcileChildFibersImpl(returnFiber,currentFirstChild,result,lanes,);// currentDebugInfo = prevDebugInfo;return firstChild;}

      1-4 检查newChild为数组类型(多个同级子节点)

       // 处理数组类型的子节点if (isArray(newChild)) {// const prevDebugInfo = pushDebugInfo(newChild._debugInfo);const firstChild = reconcileChildrenArray(returnFiber,currentFirstChild,newChild,lanes,);// currentDebugInfo = prevDebugInfo;return firstChild;}

      reconcileChildrenArray

      reconcileChildrenArray 函数是用于对比新旧子节点数组,找出它们之间的差异,然后根据这些差异更新 Fiber 树,以反映新的 UI 状态。它会对新旧子节点进行遍历和比较,执行插入、删除、移动等操作,并标记相应的副作用,最终返回新的第一个子 Fiber 节点。

      处理过程:

      1. 第一轮遍历:同步比较新旧子节点
      2. 如果新子节点遍历完,删除剩余的旧子节点,返回,结束。
      3. 如果旧子节点遍历完,创建剩余的新子节点。并将剩余的旧子节点存储到一个 Map 中
      4. 第二轮遍历:处理剩余的新子节点
      5. 删除剩余未使用的旧子节点
      function reconcileChildrenArray(returnFiber: Fiber,// 父节点currentFirstChild: Fiber | null,// newChildren: Array<any>,lanes: Lanes,): Fiber | null {// 用于存储已知的键集合,初始为 null。let knownKeys: Set<string> | null = null;// 存储新的第一个子 Fiber 节点,初始为 null。let resultingFirstChild: Fiber | null = null;// 存储上一个处理的新 Fiber 节点,初始为 null。let previousNewFiber: Fiber | null = null;// 指向当前旧的子 Fiber 节点,初始为 currentFirstChild。let oldFiber = currentFirstChild;// 记录最后一个被放置的节点的索引,初始为 0。let lastPlacedIndex = 0;// 用于遍历新子节点数组的索引,初始为 0。let newIdx = 0;// 存储下一个旧的子 Fiber 节点,初始为 null。let nextOldFiber = null;// 第一轮遍历:同步遍历新旧子节点for (; oldFiber !== null && newIdx < newChildren.length; newIdx++) {if (oldFiber.index > newIdx) {nextOldFiber = oldFiber;oldFiber = null;} else {nextOldFiber = oldFiber.sibling;}// updateSlot 函数用于尝试复用旧的 Fiber 节点或创建新的 Fiber 节点。const newFiber = updateSlot(returnFiber,oldFiber,newChildren[newIdx],lanes,);// 如果 newFiber 为 null,说明当前位置没有匹配的节点,跳出循环。if (newFiber === null) {if (oldFiber === null) {oldFiber = nextOldFiber;}break;}// 需要跟踪副作用且旧的 Fiber 节点未被复用,则调用 deleteChild 函数删除旧的子节点。if (shouldTrackSideEffects) {if (oldFiber && newFiber.alternate === null) {deleteChild(returnFiber, oldFiber);}}// placeChild 函数用于确定新 Fiber 节点的插入位置,并更新 lastPlacedIndex。lastPlacedIndex = placeChild(newFiber, lastPlacedIndex, newIdx);if (previousNewFiber === null) {// TODO: Move out of the loop. This only happens for the first run.resultingFirstChild = newFiber;} else {previousNewFiber.sibling = newFiber;}previousNewFiber = newFiber;oldFiber = nextOldFiber;}// 处理新子节点遍历完的情况if (newIdx === newChildren.length) {deleteRemainingChildren(returnFiber, oldFiber);return resultingFirstChild;}// 处理旧子节点遍历完的情况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;}// Add all children to a key map for quick lookups.// 处理剩余的新旧子节点const existingChildren = mapRemainingChildren(oldFiber);// Keep scanning and use the map to restore deleted items as moves.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;}}// 删除剩余的旧子节点if (shouldTrackSideEffects) {existingChildren.forEach(child => deleteChild(returnFiber, child));}// if (getIsHydrating()) {//   const numberOfForks = newIdx;//   pushTreeFork(returnFiber, numberOfForks);// }// 返回新的第一个子 Fiber 节点return resultingFirstChild;}
      

      1-5 检查newChild为可迭代类型

          // 处理可迭代类型的子节点if (getIteratorFn(newChild)) {// const prevDebugInfo = pushDebugInfo(newChild._debugInfo);const firstChild = reconcileChildrenIteratable(returnFiber,currentFirstChild,newChild,lanes,);// currentDebugInfo = prevDebugInfo;return firstChild;}

      reconcileChildrenIterator

      reconcileChildrenIterator 函数的主要功能是对新旧子节点进行协调,以找出它们之间的差异,并根据这些差异更新 Fiber 树。该函数接收一个迭代器 newChildren 作为新的子节点来源,会将其与旧的子 Fiber 节点进行比较,然后执行插入、删除、移动等操作,最终返回新的第一个子 Fiber 节点。

      函数参数含义

      • returnFiber:类型为 Fiber,代表父 Fiber 节点,即当前处理的子节点所属的父节点。
      • currentFirstChild:类型为 Fiber | null,表示当前父 Fiber 节点的第一个子 Fiber 节点,如果没有子节点则为 null
      • newChildren:类型为 ?Iterator<mixed>,是一个迭代器对象,用于遍历新的子节点。
      • lanes:类型为 Lanes,表示渲染优先级,用于确定此次更新的优先级。

        处理过程:

        1、同步遍历新旧节点。

        2、处理新子节点遍历完的情况。如果完毕这里结束。

        3、处理旧子节点遍历完的情况。剩余新子节点新建。

        4、处理剩余的新旧子节点,依据剩余新子节点查询就节点map中可复用的。

        5、删除剩余的旧子节点。

        6、返回新的第一个子 Fiber 节点。

        function reconcileChildrenIterator(returnFiber: Fiber,currentFirstChild: Fiber | null,newChildren: ?Iterator<mixed>,lanes: Lanes,): Fiber | null {if (newChildren == null) {throw new Error('An iterable object provided no iterator.');}// 存储新fiber的第一个子节点let resultingFirstChild: Fiber | null = null;// 存储上一个处理的新 Fiber 节点,用于构建新的 Fiber 节点链表。let previousNewFiber: Fiber | null = null;// 旧fiberlet oldFiber = currentFirstChild;// 记录最后一个放置的 Fiber 节点的索引,用于判断节点是否需要移动。let lastPlacedIndex = 0;let newIdx = 0;let nextOldFiber = null;// 下一个fiber节点// 用于存储已知的 key,初始为 null。let knownKeys: Set<string> | null = null;// 下一个新子节点let step = newChildren.next();// 1、同步遍历新旧节点for (;oldFiber !== null && !step.done;newIdx++, step = newChildren.next()) {if (oldFiber.index > newIdx) {nextOldFiber = oldFiber;oldFiber = null;} else {nextOldFiber = oldFiber.sibling;}const newFiber = updateSlot(returnFiber, oldFiber, step.value, lanes);if (newFiber === null) {if (oldFiber === null) {oldFiber = nextOldFiber;}break;}lastPlacedIndex = placeChild(newFiber, lastPlacedIndex, newIdx);if (previousNewFiber === null) {resultingFirstChild = newFiber;} else {previousNewFiber.sibling = newFiber;}previousNewFiber = newFiber;oldFiber = nextOldFiber;}// 2、处理新子节点遍历完的情况if (step.done) {deleteRemainingChildren(returnFiber, oldFiber);return resultingFirstChild;}// 3、处理旧子节点遍历完的情况if (oldFiber === null) {for (; !step.done; newIdx++, step = newChildren.next()) {const newFiber = createChild(returnFiber, step.value, lanes);if (newFiber === null) {continue;}lastPlacedIndex = placeChild(newFiber, lastPlacedIndex, newIdx);if (previousNewFiber === null) {// TODO: Move out of the loop. This only happens for the first run.resultingFirstChild = newFiber;} else {previousNewFiber.sibling = newFiber;}previousNewFiber = newFiber;}return resultingFirstChild;}// 4、处理剩余的新旧子节点// Add all children to a key map for quick lookups.const existingChildren = mapRemainingChildren(oldFiber);// Keep scanning and use the map to restore deleted items as moves.for (; !step.done; newIdx++, step = newChildren.next()) {const newFiber = updateFromMap(existingChildren,returnFiber,newIdx,step.value,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;}

        1-6 检查newChild为异步可迭代类型

            // 处理异步可迭代类型的子节点if (enableAsyncIterableChildren &&typeof newChild[ASYNC_ITERATOR] === 'function') {// const prevDebugInfo = pushDebugInfo(newChild._debugInfo);const firstChild = reconcileChildrenAsyncIteratable(returnFiber,currentFirstChild,newChild,lanes,);// currentDebugInfo = prevDebugInfo;return firstChild;}

        reconcileChildrenAsyncIteratable

        reconcileChildrenAsyncIteratable 函数主要用于处理异步可迭代的子节点。在 React 的协调过程中,当遇到异步可迭代的子节点时,该函数会对其进行处理,最终调用 reconcileChildrenIterator 函数完成子节点的协调工作。

        函数参数含义

        • returnFiber:类型为 Fiber,代表父 Fiber 节点,即当前处理的子节点所属的父节点。
        • currentFirstChild:类型为 Fiber | null,表示当前父 Fiber 节点的第一个子 Fiber 节点,如果没有子节点则为 null
        • newChildrenIterable:类型为 AsyncIterable<mixed>,是一个异步可迭代对象,包含了新的子节点数据。
        • lanes:类型为 Lanes,表示渲染优先级,用于确定此次更新的优先级。
          function reconcileChildrenAsyncIteratable(returnFiber: Fiber,currentFirstChild: Fiber | null,newChildrenIterable: AsyncIterable<mixed>,lanes: Lanes,
          ): Fiber | null {// 获取异步迭代器const newChildren = newChildrenIterable[ASYNC_ITERATOR]();if (newChildren == null) {throw new Error('An iterable object provided no iterator.');}// 创建同步迭代器const iterator: Iterator<mixed> = ({next(): IteratorResult<mixed, void> {return unwrapThenable(newChildren.next());},}: any);return reconcileChildrenIterator(returnFiber,currentFirstChild,iterator,// 同步迭代器lanes,);
          }

          1-7 检查newChild为Promise类型

              // 处理 Promise 类型的子节点if (typeof newChild.then === 'function') {const thenable: Thenable<any> = (newChild: any);// const prevDebugInfo = pushDebugInfo((thenable: any)._debugInfo);const firstChild = reconcileChildFibersImpl(returnFiber,currentFirstChild,unwrapThenable(thenable),lanes,);// currentDebugInfo = prevDebugInfo;return firstChild;}

          1-8检查newChild.$$typeof为REACT_CONTEXT_TYPE

              // 处理 React Context 类型if (newChild.$$typeof === REACT_CONTEXT_TYPE) {const context: ReactContext<mixed> = (newChild: any);return reconcileChildFibersImpl(returnFiber,currentFirstChild,readContextDuringReconciliation(returnFiber, context, lanes),lanes,);}// throwOnInvalidObjectType(returnFiber, newChild);}

           

          工具函数之readContextDuringReconciliation

          readContextDuringReconciliation 函数是会根据当前渲染状态决定是否需要初始化上下文读取环境,然后调用 readContextForConsumer 实际读取上下文值并建立依赖关系。该函数确保在协调阶段安全地读取上下文,避免因环境未准备而导致的错误。

          function readContextDuringReconciliation<T>(consumer: Fiber,context: ReactContext<T>,renderLanes: Lanes,
          ): T {
          // 当 currentlyRenderingFiber 为 null 时,表示当前没有正在渲染的 Fiber,需要初始化上下文读取环境。if (currentlyRenderingFiber === null) {prepareToReadContext(consumer, renderLanes);}return readContextForConsumer(consumer, context);
          }

           

          工具函数之prepareToReadContext

          prepareToReadContext 函数是 React 渲染流程中的关键环节,用于为当前 Fiber 节点准备上下文读取环境。它主要完成以下工作:

          1. 设置当前渲染的 Fiber 节点。
          2. 重置上下文依赖链表。
          3. 处理上下文更新标记,确保依赖的上下文变化能触发组件重新渲染。
          function prepareToReadContext(workInProgress: Fiber,renderLanes: Lanes,
          ): void {currentlyRenderingFiber = workInProgress;lastContextDependency = null;const dependencies = workInProgress.dependencies;// 处理已有的上下文依赖if (dependencies !== null) {// 启用传播模式if (enableLazyContextPropagation) {// Reset the work-in-progress listdependencies.firstContext = null;} else {const firstContext = dependencies.firstContext;if (firstContext !== null) {// 检查上下文是否有更新if (includesSomeLane(dependencies.lanes, renderLanes)) {// Context list has a pending update. Mark that this fiber performed work.// 上下文有更新,标记当前 Fiber 执行了工作markWorkInProgressReceivedUpdate();}// Reset the work-in-progress listdependencies.firstContext = null;}}}
          }

          工具函数之readContextForConsumer

          readContextForConsumer 函数是 React 中用于读取上下文(Context)值的核心内部函数,主要用于类组件和函数组件中消费上下文。它会从当前上下文对象中获取最新值,并建立上下文依赖关系,确保当上下文值变化时,组件能正确触发重新渲染。

          function readContextForConsumer<C>(consumer: Fiber | null,context: ReactContext<C>,
          ): C {// 根据当前渲染器类型(主渲染器或辅助渲染器),从上下文对象(context)中获取对应的值。const value = isPrimaryRenderer? context._currentValue: context._currentValue2;// 创建上下文依赖项const contextItem = {context: ((context: any): ReactContext<mixed>),memoizedValue: value,next: null,};// 当 lastContextDependency 为 null 时,说明组件首次读取上下文,创建新的依赖链表。if (lastContextDependency === null) {// 抛出错误:上下文只能在渲染阶段读取if (consumer === null) {throw new Error('Context can only be read while React is rendering. ' +'In classes, you can read it in the render method or getDerivedStateFromProps. ' +'In function components, you can read it directly in the function body, but not ' +'inside Hooks like useReducer() or useMemo().',);}// This is the first dependency for this component. Create a new list.// 初始化依赖链表lastContextDependency = contextItem;consumer.dependencies = {lanes: NoLanes,firstContext: contextItem,};// 启用延迟上下文传播// if (enableLazyContextPropagation) {//   consumer.flags |= NeedsPropagation;// }} else {// 非首次依赖:将新的 contextItem 追加到链表末尾,形成链式结构(next 指针串联所有依赖项)。// Append a new context item.lastContextDependency = lastContextDependency.next = contextItem;}return value;
          }

          情况2:新节点为string类型 且不为空 或新节点为number类型或者bigint类型

          if ((typeof newChild === 'string' && newChild !== '') ||typeof newChild === 'number' ||typeof newChild === 'bigint') {return placeSingleChild(reconcileSingleTextNode(returnFiber,currentFirstChild,// $FlowFixMe[unsafe-addition] Flow doesn't want us to use `+` operator with string and bigint'' + newChild,lanes,),);}
          

          reconcileSingleTextNode 

          reconcileSingleTextNode 函数的主要功能是对单个文本节点进行协调(调和)操作。在 React 的协调算法中,该函数会对比现有的子 Fiber 节点和新的文本内容,尝试复用现有的文本 Fiber 节点,若无法复用则创建新的文本 Fiber 节点,以此确保 Fiber 树能够准确反映最新的文本内容。

          函数参数含义

          • returnFiber:类型为 Fiber,代表当前文本节点的父 Fiber 节点,即新文本节点要插入到的父节点。
          • currentFirstChild:类型为 Fiber | null,表示当前父 Fiber 节点的第一个子 Fiber 节点。若不存在子节点,该值为 null
          • textContent:类型为 string,是新的文本内容。
          • lanes:类型为 Lanes,代表渲染优先级车道,用于确定此次更新的优先级。
            function reconcileSingleTextNode(returnFiber: Fiber,//父节点currentFirstChild: Fiber | null,// 第一个子节点textContent: string,lanes: Lanes,
            ): Fiber {// 检查是否有可复用的文本 Fiber 节点if (currentFirstChild !== null && currentFirstChild.tag === HostText) {deleteRemainingChildren(returnFiber, currentFirstChild.sibling);// 复用节点const existing = useFiber(currentFirstChild, textContent);existing.return = returnFiber;return existing;}deleteRemainingChildren(returnFiber, currentFirstChild);const created = createFiberFromText(textContent, returnFiber.mode, lanes);created.return = returnFiber;return created;
            }

            createFiberFromText

            createFiberFromText 函数的主要功能是依据给定的文本内容、模式和优先级车道,创建一个代表文本节点的 Fiber 节点。在 React 的 Fiber 架构里,Fiber 节点是构建虚拟 DOM 树的基本单元,此函数专门用于创建文本类型的 Fiber 节点。

            函数参数含义:

            • content:类型为 string,代表要创建的文本节点的具体内容。
            • mode:类型为TypeOfMode,表示Fiber节点的模式,该模式会影响 Fiber节点在协调过程中的行为。
            • lanes:类型为 Lanes,表示渲染优先级,用于确定该 Fiber 节点的更新优先级。
              function createFiberFromText(content: string,mode: TypeOfMode,// 并发模式,传统模式lanes: Lanes,
              ): Fiber {// HostText常量6,表示该 Fiber 节点的类型为文本节点。// 文本节点通常没有 key,所以这里传入 null。key 一般用于在列表中唯一标识元素,帮助 React 识别哪些元素发生了变化。const fiber = createFiber(HostText, content, null, mode);fiber.lanes = lanes;return fiber;
              }

              情况3:其他

              return deleteRemainingChildren(returnFiber, currentFirstChild);

              deleteRemainingChildren

              用于删除从指定 Fiber 节点开始的所有剩余子 Fiber 节点。它会根据是否需要跟踪副作用来决定是否执行删除操作,若需要跟踪,则会逐个删除子节点。

              function deleteRemainingChildren(returnFiber: Fiber,// 父节点fibercurrentFirstChild: Fiber | null,// 要删除的第一个子节点
              ): null {// 不需要跟踪副作用,,直接跳出if (!shouldTrackSideEffects) {// Noop.return null;}// 初始化 childToDelete 为 currentFirstChild,即从第一个子节点开始处理。let childToDelete = currentFirstChild;while (childToDelete !== null) {// 调用 deleteChild 函数来标记删除当前的子节点。deleteChild(returnFiber, childToDelete);// 将 childToDelete 更新为其下一个兄弟节点(通过 childToDelete.sibling),继续处理下一个子节点。childToDelete = childToDelete.sibling;}return null;
              }

              deleteChild

              deleteChild 函数的主要功能是标记一个 Fiber 节点为待删除状态。在 React 的 Fiber 架构中,删除操作不会立即执行,而是先标记需要删除的节点,等到提交阶段(commit phase)再统一处理。这样做的好处是可以批量处理删除操作,减少对 DOM 的频繁修改,提高性能。

              function deleteChild(returnFiber: Fiber,// 父节点childToDelete: Fiber// 需要删除的子节点
              ): void {// shouldTrackSideEffects 是一个布尔值,用于控制是否需要跟踪副作用。副作用在 React 中通常指的是对 DOM 进行的插入、删除、更新等操作。如果不需要跟踪副作用,函数直接返回,不进行任何操作。这是一种优化机制,避免在不需要记录删除操作时进行额外的处理。if (!shouldTrackSideEffects) {// Noop.return;}// returnFiber.deletions 是一个数组,用于存储该父节点下需要删除的子 Fiber 节点。通过将需要删除的子节点存储在这个数组中,React 可以在后续的提交阶段一次性处理这些删除操作。const deletions = returnFiber.deletions;if (deletions === null) {returnFiber.deletions = [childToDelete];// ChildDeletion 标记表示该父节点有子节点需要被删除。returnFiber.flags |= ChildDeletion;} else {// 将 childToDelete 添加到 deletions 数组中,以便后续统一处理。deletions.push(childToDelete);}
              }

               工具函数之 placeSingleChild

              placeSingleChild 函数主要用于为单个新的 Fiber 节点标记插入副作用。在 React 的协调过程中,需要确定哪些 Fiber 节点需要进行插入操作,这个函数会根据特定条件判断新的 Fiber 节点是否需要被标记为插入,并设置相应的 flags

              
              function placeSingleChild(newFiber: Fiber): Fiber {// shouldTrackSideEffects 说明是否需要跟踪 (挂载时为false, 更新时为true)// 副作用一般指的是会对外部状态产生影响的操作,像插入、删除、更新 DOM 节点等。// newFiber.alternate为null ,说明newFiber是新创建的if (shouldTrackSideEffects && newFiber.alternate === null) {newFiber.flags |= Placement | PlacementDEV;// 代表插入}return newFiber;
              }

              工具函数之 useFiber

              基于已有的 Fiber 节点创建一个新的 workInProgress(进行中的工作)Fiber 节点。workInProgress 用于表示当前正在处理的 Fiber 树,通过复用旧的 Fiber 节点可以提高性能。这个函数接收一个旧的 Fiber 节点和新的 props,然后返回一个新的 workInProgress Fiber 节点,并且会重置该节点的索引和兄弟节点信息。

              function useFiber(fiber: Fiber, pendingProps: mixed): Fiber {const clone = createWorkInProgress(fiber, pendingProps);clone.index = 0;clone.sibling = null;return clone;
              }

              工具函数之 createWorkInProgress

              createWorkInProgress用于创建或复用一个 workInProgress(进行中的工作)Fiber 节点。在 React 的渲染流程中,为了实现可中断的渲染和双缓存机制,会使用两个 Fiber 树:当前渲染的 Fiber 树(current)和正在构建的 Fiber 树(workInProgress)。这个函数的作用就是根据当前的 Fiber 节点(current)和新的待处理属性(pendingProps),创建或更新 workInProgress 节点。

              参数说明:

              • current: Fiber:当前正在渲染的 Fiber 节点。
              • pendingProps: any:新的待处理属性,用于更新 workInProgress 节点。
               function createWorkInProgress(current: Fiber, pendingProps: any): Fiber {let workInProgress = current.alternate;// 如果 workInProgress 为 null,说明还没有对应的进行中的工作节点,需要创建一个新的if (workInProgress === null) {// 创建新的 workInProgress 节点workInProgress = createFiber(current.tag,// 当前节点的类型标签(tag)pendingProps,// 待处理的propscurrent.key,current.mode,);// 复制当前节点的 elementType、type 和 stateNode 到新节点。workInProgress.elementType = current.elementType;workInProgress.type = current.type;workInProgress.stateNode = current.stateNode;// 建立 workInProgress 和 current 之间的双向引用,即 workInProgress.alternate 指向 current,current.alternate 指向 workInProgress。workInProgress.alternate = current;current.alternate = workInProgress;} else {// 复用已有的 workInProgress 节点并更新属性workInProgress.pendingProps = pendingProps;// Needed because Blocks store data on type.workInProgress.type = current.type;// We already have an alternate.// Reset the effect tag.workInProgress.flags = NoFlags;// The effects are no longer valid.workInProgress.subtreeFlags = NoFlags;workInProgress.deletions = null;}// 复制部分属性到 workInProgress 节点workInProgress.flags = current.flags & StaticMask;workInProgress.childLanes = current.childLanes;workInProgress.lanes = current.lanes;workInProgress.child = current.child;workInProgress.memoizedProps = current.memoizedProps;// 上一次的渲染属性workInProgress.memoizedState = current.memoizedState;// 上一次渲染状态workInProgress.updateQueue = current.updateQueue;// 更新队列const currentDependencies = current.dependencies;// 对于依赖项,进行浅复制,避免共享引用。workInProgress.dependencies =currentDependencies === null? null:  {lanes: currentDependencies.lanes,firstContext: currentDependencies.firstContext,};// These will be overridden during the parent's reconciliationworkInProgress.sibling = current.sibling;workInProgress.index = current.index;workInProgress.ref = current.ref;workInProgress.refCleanup = current.refCleanup;return workInProgress;
              }

              工具函数之 coerceRef

              coerceRef 函数的主要作用是将 ReactElement(即 React 元素)的 ref 属性赋值给对应的 Fiber 节点(workInProgress)。在 React 的协调过程中,Fiber 节点是协调算法的工作单元,用于表示组件树中的一个节点,而 ref 属性通常用于获取 DOM 节点或组件实例的引用。

              function coerceRef(workInProgress: Fiber, element: ReactElement): void {// 获取react元素的ref属性const refProp = element.props.ref;// should always read the ref from the prop.// 将refProp赋给当前fiberworkInProgress.ref = refProp !== undefined ? refProp : null;
              }

              工具函数之 placeChild

              placeChild 函数主要负责确定新 Fiber 节点在 Fiber 树中的位置,并根据情况标记该节点是需要移动、插入还是保持原位,同时返回更新后的 lastPlacedIndex 值。lastPlacedIndex 用于记录上一个已放置节点的索引,以此来判断当前节点是否需要移动。

              函数参数含义

              • newFiber:类型为 Fiber,代表新创建或复用的 Fiber 节点,需要为其确定在 Fiber 树中的位置。
              • lastPlacedIndex:类型为 number,表示上一个已放置节点的索引,用于判断当前节点是否需要移动。
              • newIndex:类型为 number,是新 Fiber 节点在新子节点数组中的索引。
              function placeChild(newFiber: Fiber,lastPlacedIndex: number,newIndex: number,
              ): number {// 设置新 Fiber 节点的索引newFiber.index = newIndex;// 处理不需要跟踪副作用的情况 (初始化时)if (!shouldTrackSideEffects) {newFiber.flags |= Forked;return lastPlacedIndex;}// 获取旧 Fiber 节点const current = newFiber.alternate;if (current !== null) {const oldIndex = current.index;if (oldIndex < lastPlacedIndex) {// 说明需要移动newFiber.flags |= Placement | PlacementDEV;return lastPlacedIndex;} else {// This item can stay in place.return oldIndex;}} else {// 处理不存在旧 Fiber 节点的情况// This is an insertion.newFiber.flags |= Placement | PlacementDEV;return lastPlacedIndex;}
              }

              工具函数之 createChild

              createChild 函数用于根据不同类型的 newChild 创建对应的 Fiber 节点,并将其连接到父 Fiber(returnFiber)。它是 React 协调过程中的核心函数之一,负责处理各种类型的 React 元素,包括文本节点、普通元素、Portal、延迟加载组件等。

              function createChild(returnFiber: Fiber,newChild: any,lanes: Lanes,
              ): Fiber | null {// 处理原始类型(字符串、数字、大整数)if ((typeof newChild === 'string' && newChild !== '') ||typeof newChild === 'number' ||typeof newChild === 'bigint') {const created = createFiberFromText('' + newChild,returnFiber.mode,lanes,);created.return = returnFiber;return created;}// 处理对象类型if (typeof newChild === 'object' && newChild !== null) {switch (newChild.$$typeof) {case REACT_ELEMENT_TYPE: {const created = createFiberFromElement(newChild,returnFiber.mode,lanes,);coerceRef(created, newChild);created.return = returnFiber;return created;}case REACT_PORTAL_TYPE: {const created = createFiberFromPortal(newChild,returnFiber.mode,lanes,);created.return = returnFiber;return created;}case REACT_LAZY_TYPE: {// const prevDebugInfo = pushDebugInfo(newChild._debugInfo);let resolvedChild;const payload = newChild._payload;const init = newChild._init;resolvedChild = init(payload);const created = createChild(returnFiber, resolvedChild, lanes);// currentDebugInfo = prevDebugInfo;return created;}}if (isArray(newChild) ||getIteratorFn(newChild) ||(enableAsyncIterableChildren &&typeof newChild[ASYNC_ITERATOR] === 'function')) {const created = createFiberFromFragment(newChild,returnFiber.mode,lanes,null,);created.return = returnFiber;return created;}// Usable node types//// Unwrap the inner value and recursively call this function again.if (typeof newChild.then === 'function') {const thenable: Thenable<any> = (newChild: any);// const prevDebugInfo = pushDebugInfo(newChild._debugInfo);const created = createChild(returnFiber,unwrapThenable(thenable),lanes,);// currentDebugInfo = prevDebugInfo;return created;}if (newChild.$$typeof === REACT_CONTEXT_TYPE) {const context: ReactContext<mixed> = (newChild: any);return createChild(returnFiber,readContextDuringReconciliation(returnFiber, context, lanes),lanes,);}// throwOnInvalidObjectType(returnFiber, newChild);}return null;
              }

              工具函数之 updateSlot

              updateSlot 函数主要用于根据新的子元素(newChild)和旧 fiber(oldFiber)来更新父 fiber(returnFiber)的插槽内容。它会根据子元素的类型(文本、对象、数组、可迭代对象、Promise 等)进行不同的处理,以实现对纤维的更新或返回 null(当键不匹配或无法处理子元素类型时)。

              function updateSlot(returnFiber: Fiber,oldFiber: Fiber | null,newChild: any,lanes: Lanes,
              ): Fiber | null {// Update the fiber if the keys match, otherwise return null.const key = oldFiber !== null ? oldFiber.key : null;if ((typeof newChild === 'string' && newChild !== '') ||typeof newChild === 'number' ||typeof newChild === 'bigint') {if (key !== null) {return null;}return updateTextNode(returnFiber,oldFiber,'' + newChild,lanes,);}if (typeof newChild === 'object' && newChild !== null) {switch (newChild.$$typeof) {case REACT_ELEMENT_TYPE: {if (newChild.key === key) {const updated = updateElement(returnFiber,oldFiber,newChild,lanes,);return updated;} else {return null;}}case REACT_PORTAL_TYPE: {if (newChild.key === key) {return updatePortal(returnFiber, oldFiber, newChild, lanes);} else {return null;}}case REACT_LAZY_TYPE: {let resolvedChild;const payload = newChild._payload;const init = newChild._init;resolvedChild = init(payload);const updated = updateSlot(returnFiber,oldFiber,resolvedChild,lanes,);return updated;}}if (isArray(newChild) ||getIteratorFn(newChild) ||(enableAsyncIterableChildren &&typeof newChild[ASYNC_ITERATOR] === 'function')) {if (key !== null) {return null;}const updated = updateFragment(returnFiber,oldFiber,newChild,lanes,null,);return updated;}// Usable node types//// Unwrap the inner value and recursively call this function again.if (typeof newChild.then === 'function') {const thenable: Thenable<any> = (newChild: any);const updated = updateSlot(returnFiber,oldFiber,unwrapThenable(thenable),lanes,);return updated;}if (newChild.$$typeof === REACT_CONTEXT_TYPE) {const context: ReactContext<mixed> = (newChild: any);return updateSlot(returnFiber,oldFiber,readContextDuringReconciliation(returnFiber, context, lanes),lanes,);}throwOnInvalidObjectType(returnFiber, newChild);}return null;
              }

              工具函数之 mapRemainingChildren

              创建一个新的 Map 对象 existingChildren,用于存储子 Fiber 节点。Map 的键可以是字符串类型(当子 Fiber 节点有 key 属性时)或者数字类型(当子 Fiber 节点没有 key 属性时,使用其 index 作为键),值为对应的 Fiber 节点。

              function mapRemainingChildren(currentFirstChild: Fiber,//当前父 Fiber 节点的第一个子 Fiber 节点。
              ): Map<string | number, Fiber> {const existingChildren: Map<string | number, Fiber> = new Map();let existingChild: null | Fiber = currentFirstChild;while (existingChild !== null) {if (existingChild.key !== null) {existingChildren.set(existingChild.key, existingChild);} else {// 用索引作为keyexistingChildren.set(existingChild.index, existingChild);}// 处理下一个兄弟节点existingChild = existingChild.sibling;}//  返回存储子 Fiber 节点的 Mapreturn existingChildren;
              }

              工具函数之 updateFromMap

              updateFromMap 函数主要用于处理以 Map 结构存储的现有子节点existingChildren)与新子节点(newChild)的匹配和更新逻辑。它会根据子节点的类型(文本、元素、Portal、延迟加载组件等),从 Map 中查找匹配的旧纤维(Fiber),并执行更新、复用或创建操作。

              function updateFromMap(existingChildren: Map<string | number, Fiber>,returnFiber: Fiber,newIdx: number,newChild: any,lanes: Lanes,
              ): Fiber | null {// 处理普通类型的if ((typeof newChild === 'string' && newChild !== '') ||typeof newChild === 'number' ||typeof newChild === 'bigint') {const matchedFiber = existingChildren.get(newIdx) || null;return updateTextNode(returnFiber,matchedFiber,'' + newChild,lanes,);}// 处理对象类型if (typeof newChild === 'object' && newChild !== null) {switch (newChild.$$typeof) {case REACT_ELEMENT_TYPE: {const matchedFiber =existingChildren.get(newChild.key === null ? newIdx : newChild.key,) || null;// const prevDebugInfo = pushDebugInfo(newChild._debugInfo);const updated = updateElement(returnFiber,matchedFiber,newChild,lanes,);// currentDebugInfo = prevDebugInfo;return updated;}case REACT_PORTAL_TYPE: {const matchedFiber =existingChildren.get(newChild.key === null ? newIdx : newChild.key,) || null;return updatePortal(returnFiber, matchedFiber, newChild, lanes);}case REACT_LAZY_TYPE: {// const prevDebugInfo = pushDebugInfo(newChild._debugInfo);let resolvedChild;const payload = newChild._payload;const init = newChild._init;resolvedChild = init(payload);const updated = updateFromMap(existingChildren,returnFiber,newIdx,resolvedChild,lanes,);// currentDebugInfo = prevDebugInfo;return updated;}}if (isArray(newChild) ||getIteratorFn(newChild) ||(enableAsyncIterableChildren &&typeof newChild[ASYNC_ITERATOR] === 'function')) {const matchedFiber = existingChildren.get(newIdx) || null;// const prevDebugInfo = pushDebugInfo(newChild._debugInfo);const updated = updateFragment(returnFiber,matchedFiber,newChild,lanes,null,);// currentDebugInfo = prevDebugInfo;return updated;}// Usable node types//// Unwrap the inner value and recursively call this function again.if (typeof newChild.then === 'function') {const thenable: Thenable<any> = (newChild: any);// const prevDebugInfo = pushDebugInfo((thenable: any)._debugInfo);const updated = updateFromMap(existingChildren,returnFiber,newIdx,unwrapThenable(thenable),lanes,);// currentDebugInfo = prevDebugInfo;return updated;}if (newChild.$$typeof === REACT_CONTEXT_TYPE) {const context: ReactContext<mixed> = (newChild: any);return updateFromMap(existingChildren,returnFiber,newIdx,readContextDuringReconciliation(returnFiber, context, lanes),lanes,);}// throwOnInvalidObjectType(returnFiber, newChild);}return null;
              }

               

              工具函数之 updateElement

              updateElement 函数用于处理 React 元素的更新或创建操作。它会根据元素类型、当前纤维状态以及新旧元素的匹配情况,决定是复用现有 fiber(useFiber)还是创建新 fiber(createFiberFromElement)。该函数是 React 协调过程的核心部分,负责处理普通元素和 Fragment 类型的更新逻辑。

              function updateElement(returnFiber: Fiber,current: Fiber | null,element: ReactElement,lanes: Lanes,
              ): Fiber {const elementType = element.type;if (elementType === REACT_FRAGMENT_TYPE) {const updated = updateFragment(returnFiber,current,element.props.children,lanes,element.key,);// validateFragmentProps(element, updated, returnFiber);return updated;}if (current !== null) {if (current.elementType === elementType ||(typeof elementType === 'object' &&elementType !== null &&elementType.$$typeof === REACT_LAZY_TYPE &&resolveLazy(elementType) === current.type)) {// Move based on indexconst existing = useFiber(current, element.props);coerceRef(existing, element);existing.return = returnFiber;return existing;}}// Insertconst created = createFiberFromElement(element, returnFiber.mode, lanes);coerceRef(created, element);created.return = returnFiber;return created;
              }

              工具函数之 updateFragement

              function updateFragment(returnFiber: Fiber,current: Fiber | null,fragment: Iterable<React$Node>,lanes: Lanes,key: null | string,
              ): Fiber {if (current === null || current.tag !== Fragment) {// Insertconst created = createFiberFromFragment(fragment,returnFiber.mode,lanes,key,);created.return = returnFiber;return created;} else {// Updateconst existing = useFiber(current, fragment);existing.return = returnFiber;return existing;}
              }

              工具函数之 updateTextNode

              updateTextNode 函数用于处理文本节点的更新或创建操作。它会根据当前是否存在旧 fiber(current)以及旧 fiber 的类型,决定是复用现有 fiber 还是创建新 fiber。

              function updateTextNode(returnFiber: Fiber,current: Fiber | null,textContent: string,lanes: Lanes,
              ) {if (current === null || current.tag !== HostText) {// Insertconst created = createFiberFromText(textContent, returnFiber.mode, lanes);created.return = returnFiber;return created;} else {// Updateconst existing = useFiber(current, textContent);existing.return = returnFiber;return existing;}
              }

              全局变量

              export const FunctionComponent = 0;
              export const ClassComponent = 1;
              export const HostRoot = 3; // Root of a host tree. Could be nested inside another node.
              export const HostPortal = 4; // A subtree. Could be an entry point to a different renderer.
              export const HostComponent = 5;
              export const HostText = 6;
              export const Fragment = 7;
              export const Mode = 8;
              export const ContextConsumer = 9;
              export const ContextProvider = 10;
              export const ForwardRef = 11;
              export const Profiler = 12;
              export const SuspenseComponent = 13;
              export const MemoComponent = 14;
              export const SimpleMemoComponent = 15;
              export const LazyComponent = 16;
              export const IncompleteClassComponent = 17;
              export const DehydratedFragment = 18;
              export const SuspenseListComponent = 19;
              export const ScopeComponent = 21;
              export const OffscreenComponent = 22;
              export const LegacyHiddenComponent = 23;
              export const CacheComponent = 24;
              export const TracingMarkerComponent = 25;
              export const HostHoistable = 26;
              export const HostSingleton = 27;
              export const IncompleteFunctionComponent = 28;
              export const Throw = 29;
              

              fiber树结构

              <div><p></p><div></div><span></span>
              </div>

              react支持浏览器的内置组件

              React DOM 组件 – React 中文文档

              1、通用组件(如 <div>)

              这些组件在 React 中可以使用 React 特有的属性,如 ref 与 dangerouslySetInnerHTML。

              2、表单组件

              • <input>
              • <select>
              • <textarea>

              将 value 作为 prop 传递给这些组件会将其变为 受控组件。

              3、资源和mata组件

              • <link>
              • <meta>
              • <script>
              • <style>
              • <title>

              4、所有html组件

              <aside>
              <audio>
              <b>
              <base>
              <bdi>
              <bdo>
              <blockquote>
              <body>
              <br>等等

              5、所有svg组件

               

              单例宿主组件(HostSingleton

              一、定义

              单例宿主组件指的是在整个 React 应用中只能存在一个实例的宿主组件。宿主组件一般代表原生 DOM 元素,像 <div><span> 这类。单例宿主组件可能和特定的 DOM 元素或者系统资源有关,这些资源在应用里仅允许有一个实例。

              二、用途

              • 资源管理:在某些场景下,应用仅需一个特定的 DOM 元素或者系统资源,例如全局的模态框、全局的通知栏等。使用单例宿主组件可以保证这些资源仅被创建一次,避免资源的重复创建与浪费。
              • 状态管理:单例宿主组件可以用来管理全局状态。因为只有一个实例,所以状态的管理会更加简单和可控。

               

              可提升的宿主组件(HostHoistable)

              一、定义

              可提升的宿主组件是指那些可以被提升到更高级别 DOM 树中的宿主组件。提升操作通常是为了优化渲染性能,减少不必要的 DOM 操作。

              二、用途

              • 性能优化:当某些宿主组件的渲染频率较高或者对性能影响较大时,将它们提升到更高级别的 DOM 树中,可以减少这些组件的重新渲染次数,从而提升应用的性能。
              • 减少 DOM 操作:通过提升组件,可以避免在每次渲染时都创建和销毁这些组件对应的 DOM 元素,减少 DOM 操作的开销。

              相关文章:

              React19源码系列之 Diff算法

              在之前文章中root.render执行的过程&#xff0c;beginWork函数是渲染过程的核心&#xff0c;其针对不同类型的fiber进行不同的更新处理&#xff0c;在FunctionComponent&#xff08;函数组件&#xff09;中&#xff0c;会针对新旧fiber进行对比处理生成新fiber。因此此次就详细…...

              华为2024年报:鸿蒙生态正在取得历史性突破

              华为于2025年03月31日发布2024年年度报告。报告显示&#xff0c;华为经营结果符合预期&#xff0c;实现全球销售收入 8,621 亿元人民币&#xff0c;净利润 626 亿元人民币。2024 年研发投入达到 1,797 亿元人民币&#xff0c;约占全年收入的 20.8%&#xff0c;近十年累计投入的…...

              如何在Firefox火狐浏览器里-安装梦精灵AI提示词管理工具

              第一步&#xff1a;进入《梦精灵跨平台AI提示词管理工具》官网 梦精灵 跨平台AI提示词管理助手 - 官网梦精灵是一款专为AI用户打造的跨平台提示词管理插件&#xff0c;支持一键收藏、快速复制、智能分类等功能&#xff0c;适用于即梦、豆包、Kimi、DeepSeek等多个AI平台&…...

              【鸿蒙开发】性能优化

              语言层面的优化 使用明确的数据类型&#xff0c;避免使用模糊的数据类型&#xff0c;例如ESObject。 使用AOT模式 AOT就是提前编译&#xff0c;将字节码提前编译成机器码&#xff0c;这样可以充分优化&#xff0c;从而加快执行速度。 未启用AOT时&#xff0c;一边运行一边进…...

              Makefile与CMake

              一、Makefile 核心内容 1. Makefile 基础结构与工作原理 三要素&#xff1a; 目标&#xff08;Target&#xff09;&#xff1a;要生成的文件或执行的操作&#xff08;如可执行文件、清理操作&#xff09;。依赖&#xff08;Dependency&#xff09;&#xff1a;生成目标所需的…...

              P8803 [蓝桥杯 2022 国 B] 费用报销

              P8803 [蓝桥杯 2022 国 B] 费用报销 - 洛谷 题目描述 小明在出差结束后返回了公司所在的城市&#xff0c;在填写差旅报销申请时&#xff0c;粗心的小明发现自己弄丢了出差过程中的票据。 为了弥补小明的损失&#xff0c;公司同意小明用别的票据进行报销&#xff0c;但是公司财…...

              11 web 自动化之 DDT 数据驱动详解

              文章目录 一、DDT 数据驱动介绍二、实战 一、DDT 数据驱动介绍 数据驱动&#xff1a; 现在主流的设计模式之一&#xff08;以数据驱动测试&#xff09; 结合 unittest 框架如何实现数据驱动&#xff1f; ddt 模块实现 数据驱动的意义&#xff1a; 通过不同的数据对同一脚本实现…...

              15:00开始面试,15:06就出来了,问的问题有点变态。。。

              从小厂出来&#xff0c;没想到在另一家公司又寄了。 到这家公司开始上班&#xff0c;加班是每天必不可少的&#xff0c;看在钱给的比较多的份上&#xff0c;就不太计较了。没想到4月一纸通知&#xff0c;所有人不准加班&#xff0c;加班费不仅没有了&#xff0c;薪资还要降40%…...

              深入理解浏览器渲染引擎:底层机制与性能优化实战

              现代浏览器背后是一个庞大而复杂的系统工程&#xff0c;渲染引擎作为核心模块之一&#xff0c;承担着从解析 HTML/CSS 到最终绘制页面的关键职责。本文将从底层机制出发&#xff0c;系统梳理渲染引擎&#xff08;如 Blink&#xff09;工作原理、V8 与渲染流程的协作方式&#x…...

              【LeetCode 热题 100】56. 合并区间 —— 一文弄懂排序+遍历经典解法(附Python代码)

              📌 题目链接 LeetCode 56. 合并区间 📖 一、引言:区间合并,刷题路上的绊脚石? 区间类问题是算法面试中常见的经典题型,尤其是“合并区间”问题,考察你对排序、区间重叠判断及边界处理的理解和编码能力。 很多同学在面对这题时,容易卡在: 什么时候两个区间算重叠?…...

              使用Mathematica绘制Clifford奇异吸引子

              Clifford Attractors 是一种由微分方程 生成的混沌吸引子&#xff0c;参数a,b,c,d不同会产生不同的分形图案。这类吸引子属于迭代函数系统&#xff0c;通过不断迭代参数方程来生成复杂的图形。其数学基础可能与 Clifford 代数或高维函数理论相关&#xff0c;例如 Clifford 代数…...

              各个历史版本mysql/tomcat/Redis/Jdk/Apache下载地址

              mysql 各版本下载地址&#xff1a; https://downloads.mysql.com/archives/community/ **************************************************************** tomcat 各版本下载地址&#xff1a; https://archive.apache.org/dist/tomcat/ ********************************…...

              全面解析机器学习与深度学习中的模型权重文件格式与应用场景

              概述 随着机器学习和人工智能技术的飞速发展&#xff0c;高效且安全地存储、共享和部署训练有素的模型的方法变得越来越重要。模型权重文件格式在这个过程中发挥着关键作用。这些格式不仅保存了模型的学习参数&#xff0c;还能够实现可复现性&#xff0c;并且便于在各种不同环…...

              鸿蒙OSUniApp 实现的地图定位与导航功能#三方框架 #Uniapp

              UniApp 实现的地图定位与导航功能 随着移动互联网的发展&#xff0c;地图定位与导航功能已成为众多应用的标配。本文将详细介绍如何在 UniApp 框架下实现地图定位与导航功能&#xff0c;并探讨如何适配鸿蒙系统&#xff0c;助力开发者打造更加流畅的地图体验。 前言 最近在做一…...

              【HarmonyOS 5】鸿蒙星闪NearLink详解

              【HarmonyOS 5】鸿蒙星闪NearLink详解 一、前言 鸿蒙星闪NearLink Kit 是 HarmonyOS 提供的短距离通信服务&#xff0c;支持星闪设备间的连接、数据交互。例如&#xff0c;手机可作为中心设备与外围设备&#xff08;如鼠标、手写笔、智能家电、车钥匙等&#xff09;通过星闪进…...

              Java并发编程面试题总结

              目录 线程有哪几种状态?状态如何流转? 创建线程的方式? 多线程有什么应用? 线程池的好处? 线程池的七个参数? 为什么不推荐使用jdk的Executors创建线程池? 线程池的执行流程? 任务拒绝策略有哪些&#xff0c;怎么选择? 线程池的核心线程数和最大线程数怎么设定…...

              LAMP项目部署实战

              一、LAMP部署前期准备 1.1 关闭防火墙 # systemctl stop firewalld # systemctl disable firewalld 1.2 关闭SELinux SELinux(Security-EnhancedLinux)是美国国家安全局&#xff08;NSA&#xff09;对于强制访问控制的实现&#xff0c;是Linux历史上最杰出的新安全子系统。 …...

              Dify与n8n全面对比指南:AI应用开发与工作流自动化平台选择【2025最新】

              Dify与n8n全面对比指南&#xff1a;AI应用开发与工作流自动化平台选择【2025最新】 随着AI技术与自动化工具的迅速发展&#xff0c;开发者和企业面临着多种平台选择。Dify和n8n作为两个备受关注的自动化平台&#xff0c;分别专注于不同领域&#xff1a;Dify主要面向AI应用开发&…...

              VBA_NZ系列工具NZ10:VBA压缩与解压工具

              我的教程一共九套及VBA汉英手册一部&#xff0c;分为初级、中级、高级三大部分。是对VBA的系统讲解&#xff0c;从简单的入门&#xff0c;到数据库&#xff0c;到字典&#xff0c;到高级的网抓及类的应用。大家在学习的过程中可能会存在困惑&#xff0c;这么多知识点该如何组织…...

              EFT不过整改思路与调试经验

              EFT是如何影响EUT的&#xff1a; EFT试验是为了验证电气和电子设备对诸如来自切换瞬态过程(切断感性负载、继电器触点弹跳等)的各种类型瞬变骚扰的抗扰度。EFT干扰是在电路中感性负载断开时产生的&#xff0c;它的特点是干扰信号不是单个脉而是一连串的脉冲群。EFT 干扰可以在…...

              2.安卓逆向2-adb指令

              免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 内容参考于&#xff1a;图灵Python学院 工具下载&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1bb8NhJc9eTuLzQr39lF55Q?pwdzy89 提取码&#xff1…...

              VSCode CMake工作流

              Foreword 之前看到CMake有这么多选项&#xff0c;感觉不简单&#xff0c;还是看下别人在这里设计了多少东西 CMake 整体来说CMake遵循这样一套结构 操作-操作预设&#xff08;如果有的话&#xff09;-操作目标&#xff08;如果有的话&#xff09;比如 Configure-Configure…...

              【上位机——WPF】App.xml和Application类简介

              App.xml和Application类简介 概述App.xamlApp.xaml.cs 入门代码App.xamlMainWindow.xml Application生命周期窗体的声明周期 概述 xaml类型的文件包含两部分&#xff0c;一部分以.xaml扩展名结尾的前端代码&#xff0c;另一部分以.xaml.cs结尾的后端代码&#xff0c;通常我们也…...

              MySQL 8.0 OCP 1Z0-908 101-110题

              Q101.which two queries are examples of successful SQL injection attacks? A.SELECT id, name FROM backup_before WHERE name‘; DROP TABLE injection; --’; B. SELECT id, name FROM user WHERE id23 oR id32 OR 11; C. SELECT id, name FROM user WHERE user.id (SEL…...

              Linux/Centos7离线安装并配置MySQL 5.7

              文章目录 前言1、安装包下载2、卸载MariaDB3、创建MySQL用户4、上传安装包5、创建数据目录和配置文件6、安装MySQL7、启动MySQL8、初始化MySQL9、退出验证新密码10、创建普通用户和库11、测试普通用户和库总结 前言 博主参考了一些大佬的文章&#xff0c;部分收费的就看不了了&…...

              在Angular中使用Leaflet构建地图应用

              Leaflet是一个用于创建地图的JavaScript库&#xff0c;它包含许多功能&#xff0c;并且非常适用于移动设备。 准备 nodejs: v20.15.0 npm: 10.7.0 angular: 19.2.10 创建一个地图应用工程 npx angular/cli new my-leaflet-app --stylecss --routingfalse --skip-tests提示 …...

              GPU与NPU异构计算任务划分算法研究:基于强化学习的Transformer负载均衡实践

              点击 “AladdinEdu&#xff0c;同学们用得起的【H卡】算力平台”&#xff0c;H卡级别算力&#xff0c;按量计费&#xff0c;灵活弹性&#xff0c;顶级配置&#xff0c;学生专属优惠。 引言 在边缘计算与AI推理场景中&#xff0c;GPU-NPU异构计算架构已成为突破算力瓶颈的关键技…...

              iOS 抓包实战:从 Charles 到Sniffmaster 的日常工具对比与使用经验

              iOS 抓包实战&#xff1a;从 Charles 到抓包大师 Sniffmaster 的日常工具对比与使用经验 抓包这件事&#xff0c;不是高级黑客才要做的。作为一名移动端开发&#xff0c;我几乎每天都要和网络请求打交道&#xff0c;尤其是 HTTPS 请求——加密、重定向、校验证书&#xff0c;各…...

              【微服务】SpringBoot + Docker 实现微服务容器多节点负载均衡详解

              目录 一、前言 二、前置准备 2.1 基本环境 2.2 准备一个springboot工程 2.2.1 准备几个测试接口 2.3 准备Dockerfile文件 2.4 打包上传到服务器 三、制作微服务镜像与运行服务镜像 3.1 拷贝Dockerfile文件到服务器 3.2 制作服务镜像 3.3 启动镜像服务 3.4 访问一下服…...

              【Linux系统】从 C 语言文件操作到系统调用的核心原理

              文章目录 前言lesson 15_基础IO一、共识原理二、回顾C语言接口2.1 文件的打开操作2.2 文件的读取与写入操作2.3 三个标准输入输出流 三、过渡到系统&#xff0c;认识文件系统调用3.1 open 系统调用1. 比特位标志位示例 3.2 write 系统调用1. 模拟实现 w 选项2. 模拟实现 a 选项…...

              俄罗斯方块算法

              俄罗斯方块是一款风靡全球 38 年的经典益智游戏&#xff0c;凭借其简单易学但难于精通的特点&#xff0c;成为游戏史上的不朽之作。 游戏界面与规则 游戏界面为 20 行10 列的可视区域。横向 X 轴区间为 [0&#xff0c;9]&#xff0c;共 10 列&#xff1b;纵向 Y 轴区间为 [0&a…...

              Node.js 循环依赖问题详解:原理、案例与解决方案

              文章目录 一、什么是循环依赖&#xff1f;二、循环依赖的典型表现三、解决方案四、如何检测循环依赖五、循环依赖的隐藏危害 一、什么是循环依赖&#xff1f; 当两个或者多个模块互相直接或者间接引用时&#xff0c;就会形成循环依赖。例如&#xff1a; A.js → 依赖 → B.js…...

              Linux系统编程——vfork函数的使用方法以及与fork函数的区别

              vfork() 是 Linux 系统编程中与 fork() 类似的系统调用&#xff0c;用于创建一个新的子进程。它们都能创建子进程&#xff0c;但在实现机制和使用场景上有明显区别。 以下是对 vfork() 的详细介绍&#xff0c;包括&#xff1a; 使用方法 注意事项 与 fork() 的联系与区别 使…...

              .NET 无侵入自动化探针原理与主流实现详解

              目录 引言 一、.NET 无侵入自动化探针的原理 1.1 CLR Profiling API 核心机制 示例代码 1.2 CLR Instrumentation 核心机制 示例代码 1.3 反射和动态代理 核心机制 示例代码 1.4 DiagnosticSource 核心机制 示例代码 二、主流实现与工具 2.1 AppDynamics 实现原…...

              大数据:新能源汽车宇宙的未来曲率引擎

              ** 发布日期&#xff1a;2025-05-14** 关键词&#xff1a;大数据、新能源、机器学习、碳中和、CSDN爆款 1. 大数据科普&#xff1a;定义、特征与技术核心 1.1 什么是大数据&#xff1f; 大数据&#xff08;Big Data&#xff09;指规模巨大、类型多样、生成速度快且价值密度低…...

              创建你的第一个MCP服务

              创建你的第一个MCP服务 Model Context Protocol (MCP) 中国天气查询服务创建教程 什么是 Model Context Protocol (MCP) Model Context Protocol (MCP) 是一种开放标准协议&#xff0c;允许大型语言模型&#xff08;LLM&#xff09;如 Claude 与外部系统和数据源进行交互。通…...

              说一说Node.js高性能开发中的I/O操作

              众所周知&#xff0c;在软件开发的领域中&#xff0c;输入输出&#xff08;I/O&#xff09;操作是程序与外部世界交互的重要环节&#xff0c;比如从文件读取数据、向网络发送请求等。这段时间&#xff0c;也指导项目中一些项目的开发工作&#xff0c;发现在Node.js运用中&#…...

              小白入门:GitHub 远程仓库使用全攻略

              一、Git 核心概念 1. 三个工作区域 工作区&#xff08;Working Directory&#xff09;&#xff1a;实际编辑文件的地方。 暂存区&#xff08;Staging Area&#xff09;&#xff1a;准备提交的文件集合&#xff08;使用git add操作&#xff09;。 本地仓库&#xff08;Local…...

              Protobuf3协议关键字详解与应用实例

              一、核心语法与基础关键字 syntax 声明协议版本&#xff0c;必须为文件的第一行非空、非注释内容。 syntax "proto3"; // 显式指定proto3语法&#xff0c;否则编译器默认使用proto2message 定义消息类型&#xff0c;包含一组结构化字段。支持嵌套消息定义&#xff…...

              阿克曼-幻宇机器人系列教程3- 机器人交互实践(Message)

              上一篇文章介绍了如何通过topic操作命令实现与机器人的交互&#xff0c;本篇我们介绍如何通过Message&#xff08;即topic的下一级&#xff09;实现与机器人的交互。 和topic一样&#xff0c;首先在一个终端通过ssh命令登录机器人、启动机器人&#xff0c;然后打开另外一个终端…...

              Leetcode刷题 | Day63_图论08_拓扑排序

              一、学习任务 拓扑排序代码随想录 二、具体题目 1.拓扑排序117. 软件构建 【题目描述】 某个大型软件项目的构建系统拥有 N 个文件&#xff0c;文件编号从 0 到 N - 1&#xff0c;在这些文件中&#xff0c;某些文件依赖于其他文件的内容&#xff0c;这意味着如果文件 A 依…...

              [Harmony]获取资源文件中.txt文件中的字符串

              txt文件 src/main/resources/rawfile/userInfo.txt {"Code": 200,"Msg": "登录成功","RetData": {"Name": "shq","Phone": "18511111111","PostName": "按摩技师",&qu…...

              matlab多项式

              1. 多项式表示 多项式用行向量表示&#xff0c;按降幂排列系数。例如&#xff0c;多项式 3x22x1 表示为 [3 2 1]。 2. 创建多项式 直接输入系数&#xff1a;如 p [1 -3 3 -1] 表示 x3−3x23x−1。由根创建&#xff1a;使用 poly 函数。例如&#xff0c;根为 [1, 1, 1]&…...

              手搓传染病模型(SEI - SEIAR )

              在传染病防控的前沿研究中&#xff0c;构建精准的数学模型对于理解疾病传播机制、预测疫情走势以及制定有效干预策略至关重要。SEI - SEIAR 模型&#xff08;易感媒介 \(S_m\) - 潜伏媒介 \(E_m\) - 感染媒介 \(I_m\) - 易感人群 S - 潜伏人群 E - 有症状感染者 I - 无症状感染…...

              Ubuntu 安装 Redis

              1. 下载 redis 下载地址&#xff1a;https://github.com/redis/redis 2. 解压 redis 把下载的软件包&#xff0c;上传到服务器的 /usr/local 目录中&#xff0c;执行解压命令 tar -zxvf redis-8.0.1.tar.gz 3. 安装 redis 安装依赖 sudo apt-get updatesudo apt-get ins…...

              【QGIS二次开发】地图显示与交互-03

              系列目录&#xff1a; 【QGIS二次开发】地图显示与交互-01_qgis二次开发加载地图案例-CSDN博客 【QGIS二次开发】地图显示与交互-02_setlayerlabeling-CSDN博客 3. 地图符号与色表 3.1 矢量图层符号设置 任务要求&#xff1a;双击图层树节点&#xff0c;实现图层中图元的符…...

              28、动画魔法圣典:Framer Motion 时空奥义全解——React 19 交互动效

              "在数字世界的夹缝中&#xff0c;存在着连接现实与虚拟的魔法纽带——这便是 Framer Motion 的时空秘术。" ——《前端魔法师手札卷七》 一、时空裂隙动画 - FLIP量子跃迁术 1. FLIP时空扭曲原理 <motion.divlayout // 开启时空裂隙transition{{type: "spr…...

              Ken Thompson 和 Dennis Ritchie

              Ken Thompson&#xff08;肯汤普逊&#xff09;和Dennis Ritchie&#xff08;丹尼斯里奇&#xff09;是计算机科学领域的两位传奇人物&#xff0c;他们对现代计算机技术的发展产生了深远影响。以下是关于他们的详细介绍&#xff1a; 1. ​​Ken Thompson​​ ​​出生​​&am…...

              SQL:MySQL函数:条件函数(Conditional Functions)

              目录 什么是条件函数&#xff1f; 常用 MySQL 条件函数总览表 1️⃣ IF() – 条件判断函数&#xff08;If Statement&#xff09; 2️⃣ IFNULL() – 空值判断与替代函数&#xff08;If Null&#xff09; 3️⃣ NULLIF() – 相等返回 NULL&#xff08;Null If Equal&#…...

              初识Linux · IP分片

              目录 前言&#xff1a; IP分片 分片vs不分片 如何分片 分片举例 三个字段 前言&#xff1a; 前文IP协议上和IP协议下我们已经把IP协议的报头的大多数字段介绍了&#xff0c;唯独有三个字段现在还有介绍&#xff0c;即16位标识&#xff0c;8位协议&#xff0c;13位片偏移…...