React16源码: React中的updateHostComponent的源码实现

OrCAD Capture CIS 17.4 原理图绘制 阅读详情

updateHostComponent


1 )概述

  • 在 completeWork 阶段的 HostComponent 处理,继续前文所述
  • 在更新的逻辑里面,调用了 updateHostComponent
  • 进行前后props对应的dom的attributes变化的对比情况
  • 这个方法也是根据不同环境来定义的,我们这里只专注于 react-dom 环境

2 )源码

定位到 packages/react-reconciler/src/ReactFiberCompleteWork.js#L586

这里是 updateHostComponent 调用的地方

updateHostComponent(
  current,
  workInProgress,
  type,
  newProps,
  rootContainerInstance,
);

if (current.ref !== workInProgress.ref) {
  markRef(workInProgress);
}

接着,进入其定义

updateHostComponent = function(
  current: Fiber,
  workInProgress: Fiber,
  type: Type,
  newProps: Props,
  rootContainerInstance: Container,
) {
  // If we have an alternate, that means this is an update and we need to
  // schedule a side-effect to do the updates.
  const oldProps = current.memoizedProps;
  // 全等对象,没有变化过,直接 return
  if (oldProps === newProps) {
    // In mutation mode, this is sufficient for a bailout because
    // we won't touch this node even if children changed.
    return;
  }

  // If we get updated because one of our children updated, we don't
  // have newProps so we'll have to reuse them.
  // TODO: Split the update API as separate for the props vs. children.
  // Even better would be if children weren't special cased at all tho.
  // 获取 dom 和 context
  const instance: Instance = workInProgress.stateNode;
  const currentHostContext = getHostContext();
  // TODO: Experiencing an error where oldProps is null. Suggests a host
  // component is hitting the resume path. Figure out why. Possibly
  // related to `hidden`.
  // 注意这里,
  const updatePayload = prepareUpdate(
    instance,
    type,
    oldProps,
    newProps,
    rootContainerInstance,
    currentHostContext,
  );
  // TODO: Type this specific to this type of component.
  workInProgress.updateQueue = (updatePayload: any);
  // If the update payload indicates that there is a change or if there
  // is a new ref we mark this as an update. All the work is done in commitWork.
  if (updatePayload) {
    markUpdate(workInProgress);
  }
};
  • 进入 prepareUpdate
    // 忽略 DEV 判断,这里直接 return 了 diffProperties 的调用
    export function prepareUpdate(
      domElement: Instance,
      type: string,
      oldProps: Props,
      newProps: Props,
      rootContainerInstance: Container,
      hostContext: HostContext,
    ): null | Array<mixed> {
      if (__DEV__) {
        const hostContextDev = ((hostContext: any): HostContextDev);
        if (
          typeof newProps.children !== typeof oldProps.children &&
          (typeof newProps.children === 'string' ||
            typeof newProps.children === 'number')
        ) {
          const string = '' + newProps.children;
          const ownAncestorInfo = updatedAncestorInfo(
            hostContextDev.ancestorInfo,
            type,
          );
          validateDOMNesting(null, string, ownAncestorInfo);
        }
      }
      return diffProperties(
        domElement,
        type,
        oldProps,
        newProps,
        rootContainerInstance,
      );
    }
    
    • 进入 diffProperties
      // 这个方法和前文中的 setInitialProperties 有一定的类似, 根据不同的节点做不同的操作
      // Calculate the diff between the two objects.
      export function diffProperties(
        domElement: Element,
        tag: string,
        lastRawProps: Object,
        nextRawProps: Object,
        rootContainerElement: Element | Document,
      ): null | Array<mixed> {
        if (__DEV__) {
          validatePropertiesInDevelopment(tag, nextRawProps);
        }
      
        let updatePayload: null | Array<any> = null;
      
        let lastProps: Object;
        let nextProps: Object;
        switch (tag) {
          case 'input':
            lastProps = ReactDOMInput.getHostProps(domElement, lastRawProps);
            nextProps = ReactDOMInput.getHostProps(domElement, nextRawProps);
            updatePayload = [];
            break;
          case 'option':
            lastProps = ReactDOMOption.getHostProps(domElement, lastRawProps);
            nextProps = ReactDOMOption.getHostProps(domElement, nextRawProps);
            updatePayload = [];
            break;
          case 'select':
            lastProps = ReactDOMSelect.getHostProps(domElement, lastRawProps);
            nextProps = ReactDOMSelect.getHostProps(domElement, nextRawProps);
            updatePayload = [];
            break;
          case 'textarea':
            lastProps = ReactDOMTextarea.getHostProps(domElement, lastRawProps);
            nextProps = ReactDOMTextarea.getHostProps(domElement, nextRawProps);
            updatePayload = [];
            break;
          default:
            lastProps = lastRawProps;
            nextProps = nextRawProps;
            if (
              typeof lastProps.onClick !== 'function' &&
              typeof nextProps.onClick === 'function'
            ) {
              // TODO: This cast may not be sound for SVG, MathML or custom elements.
              trapClickOnNonInteractiveElement(((domElement: any): HTMLElement));
            }
            break;
        }
      
        assertValidProps(tag, nextProps);
      
        let propKey;
        let styleName;
        let styleUpdates = null;
        // 那么接下去会有两个循环
        // 第一个循环是循环 lastProps, 就是上一次渲染的结果产生的props
        // 这是第一次大循环: 找到在旧的props上有的属性,在新的props上没有的,也就是找到前后对比中删除的props
      
        for (propKey in lastProps) {
          // 对 新旧 props 进行循环判断: 新props有key 或 旧props没有key 或 旧props为null 则跳过此key
          if (
            nextProps.hasOwnProperty(propKey) ||
            !lastProps.hasOwnProperty(propKey) ||
            lastProps[propKey] == null
          ) {
            // 符合这个条件,不是被删除的属性,不会加到最后的 updatePayload
            continue;
          }
          // 对符合被删除属性来说,进行删除 style 的操作
          if (propKey === STYLE) {
            const lastStyle = lastProps[propKey];
            for (styleName in lastStyle) {
              if (lastStyle.hasOwnProperty(styleName)) {
                if (!styleUpdates) {
                  styleUpdates = {};
                }
                styleUpdates[styleName] = '';
              }
            }
          // 后面的其他判断,都没有做什么事情,可以跳过了
          } else if (propKey === DANGEROUSLY_SET_INNER_HTML || propKey === CHILDREN) {
            // Noop. This is handled by the clear text mechanism.
          } else if (
            propKey === SUPPRESS_CONTENT_EDITABLE_WARNING ||
            propKey === SUPPRESS_HYDRATION_WARNING
          ) {
            // Noop
          } else if (propKey === AUTOFOCUS) {
            // Noop. It doesn't work on updates anyway.
          } else if (registrationNameModules.hasOwnProperty(propKey)) {
            // This is a special case. If any listener updates we need to ensure
            // that the "current" fiber pointer gets updated so we need a commit
            // to update this element.
            if (!updatePayload) {
              updatePayload = [];
            }
          } else {
            // For all other deleted properties we add it to the queue. We use
            // the whitelist in the commit phase instead.
            // 注意这里,加入 updatePayload 的方式是 一次加入 key, value 这2个
            (updatePayload = updatePayload || []).push(propKey, null);
          }
        }
        // 这是第二次大循环, nextProps 就是新的props
        for (propKey in nextProps) {
          // 处理 新旧 props
          const nextProp = nextProps[propKey];
          const lastProp = lastProps != null ? lastProps[propKey] : undefined;
          // 新props没有这个key(这个key在原型链上,不在自己),或 两个 prop 相同,或两个prop 都为 null
          if (
            !nextProps.hasOwnProperty(propKey) ||
            nextProp === lastProp ||
            (nextProp == null && lastProp == null)
          ) {
            // 符合上述条件跳过
            continue;
          }
          // 对于 style 类型的 props 的处理, 判断每个 style 的key是否有变化
          // 下面会有两个循环来处理
          if (propKey === STYLE) {
            if (__DEV__) {
              if (nextProp) {
                // Freeze the next style object so that we can assume it won't be
                // mutated. We have already warned for this in the past.
                Object.freeze(nextProp);
              }
            }
            if (lastProp) {
              // Unset styles on `lastProp` but not on `nextProp`.
              for (styleName in lastProp) {
                if (
                  lastProp.hasOwnProperty(styleName) &&
                  (!nextProp || !nextProp.hasOwnProperty(styleName))
                ) {
                  if (!styleUpdates) {
                    styleUpdates = {};
                  }
                  styleUpdates[styleName] = '';
                }
              }
              // Update styles that changed since `lastProp`.
              for (styleName in nextProp) {
                if (
                  nextProp.hasOwnProperty(styleName) &&
                  lastProp[styleName] !== nextProp[styleName]
                ) {
                  if (!styleUpdates) {
                    styleUpdates = {};
                  }
                  styleUpdates[styleName] = nextProp[styleName];
                }
              }
            } else {
              // Relies on `updateStylesByID` not mutating `styleUpdates`.
              if (!styleUpdates) {
                if (!updatePayload) {
                  updatePayload = [];
                }
                updatePayload.push(propKey, styleUpdates);
              }
              styleUpdates = nextProp;
            }
          } else if (propKey === DANGEROUSLY_SET_INNER_HTML) {
            const nextHtml = nextProp ? nextProp[HTML] : undefined;
            const lastHtml = lastProp ? lastProp[HTML] : undefined;
            if (nextHtml != null) {
              // 两个html不相等则加入
              if (lastHtml !== nextHtml) {
                (updatePayload = updatePayload || []).push(propKey, '' + nextHtml);
              }
            } else {
              // TODO: It might be too late to clear this if we have children
              // inserted already.
            }
          } else if (propKey === CHILDREN) {
            // 对于 children 的处理
            if (
              lastProp !== nextProp &&
              (typeof nextProp === 'string' || typeof nextProp === 'number')
            ) {
              // 不同则加入
              (updatePayload = updatePayload || []).push(propKey, '' + nextProp);
            }
          } else if (
            propKey === SUPPRESS_CONTENT_EDITABLE_WARNING ||
            propKey === SUPPRESS_HYDRATION_WARNING
          ) {
            // Noop
          } else if (registrationNameModules.hasOwnProperty(propKey)) {
            // 这里是事件绑定相关的处理
            if (nextProp != null) {
              // We eagerly listen to this even though we haven't committed yet.
              if (__DEV__ && typeof nextProp !== 'function') {
                warnForInvalidEventListener(propKey, nextProp);
              }
              ensureListeningTo(rootContainerElement, propKey);
            }
            if (!updatePayload && lastProp !== nextProp) {
              // This is a special case. If any listener updates we need to ensure
              // that the "current" props pointer gets updated so we need a commit
              // to update this element.
              updatePayload = [];
            }
          } else {
            // For any other property we always add it to the queue and then we
            // filter it out using the whitelist during the commit.
            // 上面都没找到,这个属性是新增属性,直接加入
            (updatePayload = updatePayload || []).push(propKey, nextProp);
          }
        }
        // 最终处理加入 styleUpdates
        if (styleUpdates) {
          (updatePayload = updatePayload || []).push(STYLE, styleUpdates);
        }
        // 最终返回
        return updatePayload;
      }
      
    • 在 diffProperties 里的 updatePayload 一开始是一个空的数组,并且最终被return
    • 对于 completeWork 来说,拿到的 updatePayload,就是 diffProperties 和 prepareUpdate 返回过来的内容
    • 接下去,会有一个判断 if (updatePayload) {} 也就是说空数组也是符合这个判断条件的, 也会执行 markUpdate
    • 上述标记之后,在后续的 commit 的时候进行对应的操作
  • 以上是 updateHostComponent 的过程
    • 具体细节,参考代码里标注的中文文档和源码
    • vdom其实就是这些东西,通过props来进行 attributes 的判断和处理变化的过程
    • 主要是 整个 diffProperties 的处理
LSTM 深度解析从原理推演到现代序列建模的演进 LSTM(Long Short-Term Memory,长短期记忆网络)是一种特殊的递归神经网络(RNN),它通过引入记忆单元(Cell State)来解决普通RNN在长序列数据处理中的梯度消失问题。LSTM可以在长时间的序列中捕捉依赖关系,是一种非常适合处理时间序列、自然语言处理、语音识别等任务的深度学习模型。在LSTM中,记忆单元(Cell State)是一个贯穿整个序列的数据通道,用于存储和传递关键信息。记忆单元在LSTM的时间步之间保持信息的持久性,可以看作是一个长期记忆的“容器”。 阅读详情

相关推荐

Altera下载器驱动配置:手把手教程(从零实现)

详解Altera USB-Blaster驱动安装全过程,从设备识别到软件配置一步一图,解决常见连接问题,确保开发下载器正常工作,适合初学者快速上手FPGA下载调试。

weixin_35751194的博客 990

React 16.12.0 源码解读(四)之提交任务

React提交任务部分的源码梳理和解读。

Babyfaceqian的博客 384

Halcon阈值算子 -- 局部阈值之dyn_threshold

Halcon阈值算子 – dyn_threshold HALCON有很多阈值算子,接下来将一一介绍。本文先介绍dyn_threshold。 以下介绍主要参考HALCON帮助文档,并加上自己的体会。如有纰漏,欢迎留言指出 理论介绍 dyn_threshold算子的函数签名如下: dyn_threshold(OrigImage, ThresholdImage : RegionDynThresh : Offset, LightDark : ) 输入参数有: OrigImage:待处理图像 ThresholdIm

m0_47015717的博客 5386

Fix signatures do not match the previously installed version

报错信息FAILURE: Build failed with an exception.* What went wrong: Execution failed for task ':app:installDebug'. > com.android.builder.testing.api.DeviceException: com.android.ddmlib.InstallException: Fai

Wang的专栏 2万+

PROFINET方案选型指南:瑞萨/西门子/开源p-net协议栈对比实测

本文基于瑞萨RZ/N2L硬件平台,对瑞萨官方认证协议栈、西门子ERTECH及开源p-net三种PROFINET方案进行了实测对比。重点分析了PROFINET-IRT实时性、CPU/内存资源消耗、开发集成复杂度及许可证成本等核心指标,为工业设备制造商提供了从性能到商业决策的全面选型指南。

weixin_29291185的博客 214

槽型光电开关传感器原理图设计,已量产(光电传感器)

在嵌入式设备的位置限位、物料计数等场景中,槽型光电开关是性价比极高的传感器方案 —— 它通过遮挡发射器与接收器之间的光路实现电平切换,电路简单且抗干扰性优于漫反射式光耦。今天分享一个实际项目中落地的槽型光电开关检测电路,从器件选型到逻辑设计都做了简化适配,适合小批量原型或低成本产品的需求。

不脱发的程序猿 720

在react中 实现 base64的图片转换成formdata格式并实现上传功能

如果不想要服务端实现处理base64格式的图片的转换,那么在浏览器端来实现,部分属于伪代码,仅作为开发参考,请勿直接拷贝使用

Wang的专栏 8836

Unity引擎开发:复杂动作系统_动作捕捉数据的应用与整合

通过以上步骤,我们可以在Unity中有效地应用和整合动作捕捉数据,以实现更加真实和流畅的动画效果。从导入文件格式的选择,到预处理和优化,再到实时应用和调试验证,每一步都至关重要。希望本文能帮助你在Unity项目中更好地利用动作捕捉数据,提升动画质量和性能。

chenlz2007的博客 960

快速解决gradle下载慢的问题的小技巧

在ionic run 或build 或clean命令的时候,如果没有下载过gradle, 需要重新下载一次,而通过CLI的方式下载很慢,即使科学上网后,下载还是存在一些问题。这里总结一下,快速的下载安装方式。 步骤 本地安装 http-server 包, 通过 $ npm i -g http-server 的方式安装到全局 在官网上下载自己的版本,目前自带的版本是 2.14.1,其他版本可能在执行过

Wang的专栏 6714

CKA-题库-简洁参考答案-反复练习20遍-必过!!!

新版CKA考试已于2020年9月1日正式上线! 考试模式:线上考试 考试时间:2小时 认证有效期:3年 软件版本:Kubernetes v1.19 重考政策:可接受1次重考 经验水平:中級 题目数量:17题 题库量小:随机的题目重复率极高 考试时可打开两个浏览器Tab,一个是考试窗口,一个用来查阅官方文档](https://kubernetes.io/docs/) 01 Task - 英文 Create a new ClusterRole named deployment-clusterrole tha.

随笔记录-分享&记忆 7320

YOLO26涨点改进 | 小目标损失函数独家改进篇 | TGRS 2025 | 引入AdaFocalLoss损失函数,改进小目标检测,自适应聚焦小目标与样本分布不平衡,提升检测精度与训练稳定性

本文提出将AdaFocalLoss损失函数应用于YOLO26模型优化,有效提升小目标检测性能。AdaFocalLoss通过目标尺寸感知机制和IoU引导的动态调节,自动调整训练权重和聚焦程度,解决了样本不平衡问题。相比传统损失函数,它无需手动调参,能增强训练稳定性,在多尺度、复杂场景下表现优异。文章详细介绍了AdaFocalLoss的原理、优势及实现方法,并提供了代码集成指南。实验表明该方法能显著提升检测精度和鲁棒性,特别适用于小目标检测任务。

Ai缝合怪、助力小伙伴高效发论文 337

React 实现 2D 画板功能

在移动端或者PC端我们来模拟画板的实现, 支持清除和导出功能,此处简单实现,仅作开发参考。 效果演示 主要代码演示 /* 此模块用于实现签名绘图功能 */ // 需要用到的变量定义 let clickX = new Array(); let clickY = new Array(); let clickDrag = new Array(); let paint; let point...

Wang的专栏 4325

数据仓库数据质量监控和处理方法最佳实践

指的是检查数据是否存在反常或者错误的情况,例如数值反常地过大或者过小,或者超过记录的波动值,对应的规则包括数值波动检查,最大值、最小值检查,跨表准确性等。指的是检查数据是否存在缺失的情况,这里的缺失可以是整个数据集的记录缺失,也可以是某个字段记录的缺失,对应的规则包括空值检查,表总行数检查。指的是检查数据是否符合规范,是否按照规定的格式存储,对应的规则包括正则表达式检查,字段长度检查,枚举集合检查,数值范围等。指的是检查哪些数据是重复数据或者数据的哪些属性是重复的,对应的规则例如主键唯一性检查。

大模型大数据攻城狮的专栏 899

React16源码: React中LegacyContext的源码实现

对于在 beginWork 中的 context 操作,可以看上述判断成立的条件下的代码,即便有符合跳过更新的操作,依然 需要 push 和 pop 操作。如果我们可以跳出组件的更新,也就是代表着当前这个 classComponent,它的state它的props都应该是没有任何变化的。对于子组件来说,它的所有子树所获取到的context肯定是经过子组件,和上层的父组件合并的 context 了, 也就是。所以,先 push 一个老的值进去再说, 然后到后面,如果发现这个组件它是要更新的,就调用这个。

Wang的专栏 2803

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

Fix babel-preset-react-native TransformError

错误环境新版本存在不兼容,在运行 react-native run-android 的时候,发生的错误分析: babel-preset-react-native version : @3.0.0 $ react-native -v :react-native-cli: 2.0.1 react-native: 0.47.1$node -v : v7.8.0 $ npm -v :4.4.4 解决方案

Wang的专栏 2800

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

React18原理: 再聊Fiber架构下的时间分片

react的任务可以被打断,其实就是基于时间分片的,人眼最高能识别的帧数不超过30帧,电影的帧数差不多是在24,浏览器的帧率一般来说是60帧,也就是每秒60个画面, 平均一个画面大概是16.5毫秒左右,浏览器正常的工作流程是运算渲染,运算,渲染运算渲染,在浏览器里面一个运算,加上一个渲染就是一帧

Wang的专栏 2796

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

在react项目中修改webpack中本地服务器架设的目录

一个产品的上线往往会有很多的问题,现在就出现一个需求,我们是在服务器下的某个目录进行发布,而不是根服务器,服务端不想为一个项目配置ip地址,而在react项目中,默认是走的根路径,现在我们就开始修改一下它。 前提说明 如果我们需要修改手动配置webpack, 那么根据现在的版本, 我们只能执行 npm run eject, 之后就可以着手修改了。 webpack中与需求相关的...

Wang的专栏 2397

React18源码: React调度中的3种优先级类型和Lane的位运算

可以看得出来lane&-lane的结果是SyncLane,所以通过lane&-lane就能分离出最高优先级的任务。即A(cpu)>B(IO)>C(cpu).此时的需求需要将任务B从group中分离出来,先处理cpu任务A和C。在新版本的React中,还有一个新特性,就是render阶段可能被中断,在这个期间会产生一个更高优先级的任务。如上就是通过 lanes & -lanes 分离出最高优先级的任务的,我们来看一下具体的流程。也即是说lane的代表的数值越小,此次更新的优先级就越大。

Wang的专栏 2394

React18原理: 核心包结构与两大工作循环

react中的工作循环,这是它的一个最顶层的一个流程图,在这张图里面,有两个核心的大循环,第一大循环是 react-reconciler 提供的,它的核心是构建fiber树,生成任务,第二大循环是 scheduler 提供的, 它的核心是任务调度(处理任务的优先级),react的原理实际上就是两大工作循环

Wang的专栏 2356

React18原理: 生命周期中特别注意事项

生命周期就是一个组件从诞生到销毁的全过程(包含错误捕获,这里暂且不聊这个)react 在组件的生命周期中注册了一系列的钩子函数支持开发者在其中嵌入代码,并在适当的时机运行生命周期本质上就是组件中的钩子函数,主要有三个主要的钩子挂载更新卸载。

Wang的专栏 2244

React16源码: React中的beginWork的源码实现

定位到 packages/react-reconciler/src/ReactFiberBeginWork.js。整个文件 export 出去的只有 beginWork 方法。

Wang的专栏 2140

React16源码: React中的reconcileChildren的源码实现

在更新了一个节点之后,拿到它的props.children, 要根据这个children里面的 ReactElement 来去创建子树的所有的 fiber 对象, 要根据 props.children 来生成 fiber 子树,然后判断 fiber 对象它是否是可以复用的

Wang的专栏 2133

React16源码: React中的completeUnitOfWork的源码实现

各种不同类型组件的一个更新过程对应的是在执行 `performUnitOfWork` 里面 `beginWork` 阶段,它是去向下遍历一棵 fiber 树的一侧的子节点,然后遍历到叶子节点为止,以及 return 自己 child 的这种方式

Wang的专栏 2088

React18原理: 渲染与更新时的重点关注事项

react 在渲染过程中要做很多事情,所以不可能直接通过初始元素直接渲染还需要一个东西,就是虚拟节点,暂不涉及React Fiber的概念,将vDom树和Fiber 树统称为虚拟节点有了初始元素后,React 就会根据初始元素和其他可以生成虚拟节点的东西生成虚拟节点React一定是通过虚拟节点来进行渲染的对于首次挂载阶段需要了解React的渲染流程通过书写的初始元素和一些其他可以生成虚拟节点的东西来生成虚拟节点然后针对不同的节点类型去做不同的事情,最终将真实DOM挂载到页面上。

Wang的专栏 2069

21st.dev 上手教程:12000+ React 组件库怎么用,6 步从挑样式到接进 Cursor

21st.dev 收录 12000+ 个 React + Tailwind 组件、297 套整站模板与 979 套主题。本文是手把手流程版:按页面用途找组件、用复制或 shadcn CLI 落地、接入 MCP 让 Cursor 自己取代码、用整站模板开局,附 10 张真实组件截图和 4 个常见坑。

懿轩的技术小窝 232

手搓 AI Agent 02:让模型第一次“动手“——Agent Loop 与 ReAct

本系列第2篇实现Agent核心循环——ReAct模式,让模型从“被动回答”变为“主动执行”。通过LLMClient工具调用能力,构建think → act → observe闭环,首次实现模型自主调用计算器、读取结果并继续推理。代码支持安全算术、步数限制与错误隔离,升级终端REPL为可观察的智能体交互界面。每步操作清晰可见,为后续多工具、规划与协作打下基础。

快乐来自程序里 130
上一篇: React16源码: React中的completeWork对HostComponent处理的源码实现
下一篇: React16源码: React中的completeWork对HostText处理含更新的源码实现
Wang's Blog
博客等级 码龄12年 7438粉丝 2421原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wang's Blog

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值