尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
React Native列表在OpenHarmony上的高性能封装实践
1. 为什么要在OpenHarmony上重新造List这个轮子先说结论React Native在OpenHarmony上跑通Hello World只是第一步真正决定能不能上生产的是列表页。FlatList在Android和iOS上表现稳定但换到OpenHarmony环境后问题不是“性能差一点”这么简单而是底层渲染链路完全不同直接照搬会踩出一连串的兼容性坑。我当时接手这个项目时团队的目标很明确现有RN代码库要尽量复用但OpenHarmony端的体验不能打折。尝试直接跑原生FlatList后首屏白屏时间从Android的1.2秒飙到接近4秒滑动时还能明显感觉到cell的创建和回收节奏不对帧率掉到40左右。这就在告诉我们一个道理OpenHarmony的列表必须针对鸿蒙的ArkUI渲染机制单独做封装不能再指望RN自带的VirtualizedList去适配一切。为什么必须封一层而不是直接用ArkUI的List组件因为业务层写的是React组件拿到的数据是JS侧的数组直接让ArkUI去渲染原始JS对象是不现实的。我们需要做一套桥接层把RN侧的列表数据模型映射到OpenHarmony的List能力上同时把下拉刷新、上拉加载、分页占位这些业务逻辑沉淀成通用组件。这篇文章我会把整套封装方案拆开来讲包括桥接层的设计思路、JS侧组件的API设计、ArkUI原生侧的渲染实现、以及我在实际联调中遇到的性能问题和修复手段。无论你是准备把现有RN应用迁到OpenHarmony还是纯粹想了解这套跨端方案的技术细节这篇文章应该都能给你一些参考。在动手之前先看一张整体的技术路线图层级技术栈职责JS业务层React组件ListContainer数据请求、状态管理、下拉刷新/上拉加载逻辑桥接层TurboModule C-APIJS与ArkUI的数据交换、事件回调原生渲染层ArkUI List / WaterFlow实际列表渲染、cell复用、滚动调度平台适配层OpenHarmony SDK RN SDK生命周期管理、设备能力适配、异常兜底这个分层是我反复调整后的最终形态。最开始我不打算碰ArkUI原生层想纯靠RN的View嵌套去模拟列表结果500条数据就把JS线程卡死了。后来换成了原生List RN组件动态挂载的方案才算把性能拉回正常范围。后面会详细说为什么这条路走得通。1.1 核心痛点RN的VirtualizedList为什么在OpenHarmony上会“水土不服”RN的FlatList本质上是VirtualizedList的封装核心思路是只渲染视口附近的cell滚动时动态回收和创建。这套机制在Android和iOS上依赖的是各自平台的ScrollView原生实现每个cell对应一个原生View。问题在于OpenHarmony上的RN SDK还没有把VirtualizedList的底层能力完全对接。我实测下来列表滚动时cell的onLayout回调频繁触发但ArkUI侧的回收节奏和RN侧的计算逻辑对不上导致两种结果一种是JS侧以为cell还在可视区但原生侧已经回收了画面出现空白另一种是原生侧保留了大量JS创建的View内存持续增长最终应用被杀。还有一个更隐蔽的问题OpenHarmony的ArkUI框架对组件树的深度和节点数有自己的优化策略RN的View在ArkUI上映射时一屏几十个节点还好但列表滚起来后节点频繁创建销毁ArkUI的diff算法反而成了瓶颈。这个不做针对性优化体验基本没法接受。所以我才决定彻底接管列表渲染RN侧只负责提供数据和业务视图渲染交给ArkUI原生的List组件cell的创建和复用完全在ArkUI侧完成绕过VirtualizedList那套JS层面的计算。这是一个“让专业的人做专业的事”的思路。2. 桥接层设计让JS数据和ArkUI原生List互相理解桥接层是整个方案的骨架。它要解决两件核心的事一是把RN侧传入的列表数据可靠地转成ArkUI能消费的数据结构二是把ArkUI侧的滚动事件、cell点击事件、生命周期事件准确地回传给JS侧。OpenHarmony的RN SDK目前有两种桥接方式旧版的C-API直接桥接和新版的TurboModule。我建议直接用TurboModule虽然初期配置麻烦一点但后续的数据传输效率和类型安全要好很多。旧版的callback回调在频繁触发时会抖动而TurboModule支持Promise和同步调用对列表这种高频事件场景更友好。2.1 数据模型定义与类型映射先看数据从JS到ArkUI的流转过程。JS侧业务层拿到的原始数据通常是后端返回的JSON数组每一项可能是用户信息、商品信息、动态内容等任意结构。我们不能要求业务层把数据分割好再传那样就失去了封装的意义。我的方案是JS侧把整个数组一次性传给原生侧原生侧按索引访问。为此我在JS侧定义了一个统一的ListData类型// ListData.ts export interface ListDataT { data: T[]; total: number; page: number; pageSize: number; hasMore: boolean; refreshTime: number; }这里面的total和hasMore是用来控制上拉加载状态的。原生侧不关心业务字段它只需要知道数组长度、当前页码和是否还有更多来决定什么时候触发加载更多事件。TurboModule的接口定义我放在一个叫NativeListModule的模块里关键方法如下// NativeListModule.ts import { TurboModule, TurboModuleRegistry } from react-native; export interface Spec extends TurboModule { // 初始化列表传入数据数组和列表配置 initList(tag: number, data: ArrayObject, config: Object): Promiseboolean; // 追加数据上拉加载更多时调用 appendData(tag: number, data: ArrayObject): Promiseboolean; // 更新某一条数据局部刷新 updateItem(tag: number, index: number, data: Object): Promiseboolean; // 滚动到指定位置 scrollToIndex(tag: number, index: number, animated: boolean): void; // 触发列表刷新完成告诉原生侧下拉刷新的数据已就绪 finishRefresh(tag: number): void; // 触发加载更多完成 finishLoadMore(tag: number): void; } export default TurboModuleRegistry.getSpec(NativeListModule);这里我用tag来区分不同的列表实例。一个页面可能有多个列表比如首页的推荐流和个人中心的订单列表同时存在每个列表实例有自己的数据和状态原生侧通过tag查找对应的ArkUI组件实例。2.2 ArkUI侧的桥接实现细节ArkUI侧接收JS数据后不能直接用对象去驱动UI渲染。ArkUI是声明式UI框架如果直接拿JS对象当状态用ArkUI的状态管理V1/V2版本会有差异V1需要State装饰器来包装V2用ObservedV2/Trace会更灵活一些。但不管哪种直接塞一个巨大的数组都会触发全量diff性能堪忧。我的做法是在ArkUI侧维护一个轻量的数据管理器把JS传过来的数组做一个索引化处理渲染时只是按需取数据。代码层面我定义了一个ListDataSource类// ListDataSource.ets export class ListDataSource { private dataMap: Mapnumber, Object new Map(); private count: number 0; public setData(data: Object[]) { this.dataMap.clear(); this.count data.length; data.forEach((item, index) { this.dataMap.set(index, item); }); } public getItem(index: number): Object | undefined { return this.dataMap.get(index); } public getCount(): number { return this.count; } public appendItems(data: Object[]) { data.forEach((item, index) { this.dataMap.set(this.count index, item); }); this.count data.length; } public updateItem(index: number, data: Object) { this.dataMap.set(index, data); } }这样做的核心目的是让ArkUI的List组件在滚动时能按索引快速拿到数据而不需要遍历整个数组。ArkUI的LazyForEach要求数据源实现IDataSource接口它内部会维护一个key到index的映射滚动时按需调用getData方法。我们的ListDataSource把它包装一下就能直接对接LazyForEach。有一个细节需要特别注意LazyForEach的id生成规则必须稳定。我遇到过滚动时cell内容错乱的问题排查到最后是id生成规则用了index一旦数据新增或删除index变化就会导致LazyForEach复用错乱。正确的做法是根据业务数据的唯一标识来生成key如果业务数据没有唯一ID可以在JS侧先做一次数据清洗给每条数据加一个clientId字段。3. 组件API设计既要有原生List的性能又要保留RN的开发者体验光有桥接层还不够业务侧拿到的应该是一个开箱即用的React组件而不是一堆需要手动调用的原生方法。所以我在RN侧封装了一个ListContainer组件API设计尽量对齐FlatList的常用属性让业务方迁移成本尽量低。3.1 组件Props的取舍对齐FlatList还是另起炉灶先看ListContainer的props设计// ListContainer.tsx export interface ListContainerPropsT { // 数据源 data: T[]; // 渲染单个item的函数 renderItem: (item: T, index: number) React.ReactElement; // 下拉刷新配置 onRefresh?: () Promisevoid; refreshing?: boolean; // 上拉加载更多配置 onLoadMore?: () void; hasMore?: boolean; loadingMore?: boolean; // 列表配置 keyExtractor?: (item: T, index: number) string; initialNumToRender?: number; // 空态和错误态 ListEmptyComponent?: React.ComponentType | React.ReactElement; ListFooterComponent?: React.ComponentType | React.ReactElement; // 滚动事件 onEndReached?: () void; onEndReachedThreshold?: number; // 间距配置 ItemSeparatorComponent?: React.ComponentType | React.ReactElement; contentContainerStyle?: StylePropViewStyle; }对比FlatList我保留了下拉刷新、上拉加载、renderItem这些核心能力但砍掉了几个在OpenHarmony上暂时没有合理映射的属性比如horizontal横向列表、numColumns多列布局和getItemLayout固定高度优化。横向列表和多列布局在ArkUI里分别是List的水平和网格模式底层逻辑完全不同强行用一个组件兼容会把架构搞得很拧巴。我的建议是ListContainer先专注垂直单列列表横向和瀑布流后续单独封装成独立组件不污染主组件。3.2 renderItem的跨端渲染机制renderItem是RN组件里最关键的部分。它的返回值是一个React元素最终需要转成ArkUI的UI组件来渲染。这里有两种实现路线路线一通过View嵌套。renderItem返回的React组件最终渲染成RN的View再通过桥接层挂到ArkUI的cell里。优点是业务组件不用改缺点是每个cell都要创建一个RN原生Viewcell复用效率低而且RN和ArkUI之间多了一层消息传递。路线二ArkUI侧用自定义组件容器。cell的根节点是ArkUI的组件renderItem返回的React元素通过特殊的方式“注入”到这个容器里。这样cell的创建和销毁完全由ArkUI控制RN侧只负责生成业务内容。我最终选的是第二条路但做了一个折中设计cell的骨架背景、间距、分割线全部用ArkUI原生组件绘制只有真正的业务内容区域使用RN的View。这样视觉上的一致性更好而且大部分列表项的背景和间距是重复的用原生组件绘制可以显著减少RN侧的节点数。具体的实现方案是在ArkUI侧定义一个ListItemWrapper组件它接收一个RN组件的tag在aboutToAppear时向RN侧发起创建子视图的请求然后把这个子视图挂载到自己内部。这个过程在ArkUI里叫NodeContainer有很多细节要处理比如生命周期对齐、触摸事件透传后面会专门讲。3.3 常用的附加能力下拉刷新、上拉加载、空态和错误态这四项能力是列表组件的标配但它们各自的实现方案在OpenHarmony上有不同的坑拆开来说。下拉刷新我直接用了ArkUI的SwipeRefresh组件包裹List。这里要特别注意的是刷新状态的生命周期管理。JS侧的refreshing状态和ArkUI侧的刷新动画要同步不能出现JS侧已经setState了但ArkUI侧的刷新动画还没有停止的情况。我的做法是JS侧onRefresh回调触发后先把refreshing置为true等接口返回后API调用finishRefresh(tag)通知原生侧停止动画然后再把refreshing置为false。顺序不能反否则会出现刷新动画和列表状态不一致的问题。上拉加载这里有个很深的坑。以前在Android上我们习惯用onEndReached来判断是否加载更多但在OpenHarmony上List的onReachEnd事件在快速滑动时会触发得很激进经常滑动一次就触发三四次。如果不做节流分页接口会被连续调用数据就会重复。我加的方案是onReachEnd触发后立即把loadingMore置为true在接口返回前不响应任何后续事件同时利用props.hasMore做二次拦截从根上避免无效请求。空态和错误态这两种状态实际上是同一种处理逻辑——判断数据长度为0或异常时显示一个全屏占位。难点在于ArkUI原生List的header和footer机制。如果要让空态占位在List内部实现吸顶或者居中直接放在ListFooterComponent里会有布局问题。我的处理办法是当data.length为0时不让ArkUI渲染List而是在JS层渲染一个独立的空态视图这样布局逻辑完全由JS控制不依赖ArkUI的列表布局。4. 性能优化从启动白屏到丝滑滚动的完整调优过程这一章节讲的是我在真机调试中踩过的性能坑和最终的解决方案。列表组件的性能优化不是一个点而是一条链路每一个环节不处理好最终的体验都会大打折扣。4.1 启动白屏的三个根因与针对性修复React Native在OpenHarmony上启动白屏问题是社区里抱怨最多的问题之一。我调优后总结出三个根因。根因一JSBundle加载慢。OpenHarmony的RN SDK加载JSBundle的方式和Android不完全一样它对本地文件读取的优化不到位一个几兆的Bundle文件加载耗时可能翻倍。这个问题在列表页首屏尤为明显因为列表页通常有大量的业务逻辑注入。我的修复方案把JSBundle提前拆包首屏需要的核心代码打成一个体积较小的包列表相关的业务代码走异步加载。等到列表页真正打开时核心代码已经激活再异步补齐业务代码。这样做启动时间能优化30%以上。根因二ArkUI侧的List初始化时一次性渲染了过多cell。我在配置initialNumToRender时最初设成了20想着首屏显示10条加上预渲染10条体验会更平滑。但实际上OpenHarmony的List渲染性能和Android差距很大一次性渲染20个cell会导致首屏卡顿。后来我把initialNumToRender调成5预渲染数量调成3首屏时间缩减了一半以上。这个参数不能照搬Android经验OpenHarmony的渲染引擎对节点数和组件树的敏感度更高宁可少预渲染一点先让首屏出来后续滚动的时候再动态补。根因三图片加载阻塞了列表渲染。列表项里只要有网络图片图片解码的耗时就会阻塞整个cell的渲染。Android上Glide有异步解码的能力但OpenHarmony的Image组件在网络图片加载上还需要适配。我的方案是所有列表项中的图片在JS侧先做一个预解码标记非首屏的图片延迟加载等cell真正进入视口前100ms再发起图片请求。这三招组合起来我的列表页首屏白屏时间从4秒降到了1.5秒以内。虽然离Android的1.2秒还有一点差距但已经处于可接受的范围内。4.2 cell复用机制的二次优化ArkUI的LazyForEach自带cell复用能力但默认复用策略比较保守。它在滚动时会保留离屏的cell一段时间方便快速回滚。但如果列表项高度不固定复用时的布局计算会消耗大量时间。我做了两件事来优化第一如果业务列表的高度是可以预估的我建议在JS侧给每个item一个预估高度字段传给ArkUI后ArkUI在布局时可以跳过一部分高度测量直接按预估高度排布。等真正的布局数据出来后再矫正。// ListContainer.tsx 内部处理逻辑 const estimatedHeight item.estimatedHeight || DEFAULT_ITEM_HEIGHT; // 通过桥接层传给ArkUI NativeListModule.setEstimatedHeight(tag, index, estimatedHeight);第二cell的根布局尽量减少嵌套层级。有些组件为了视觉效果包了三四层View这在列表场景里是致命的。ArkUI对组件树的深度有很明显的性能拐点深度超过5层后渲染耗时指数级上升。我在代码审查时专门要求列表项的renderItem返回的组件层级不能超过3层嵌套太深的磨平之后再提交。4.3 滚动帧率调优事件节流与渲染优先级列表滚动时的帧率问题通常在真机上比模拟器更容易暴露。我测试时发现快速滑动时帧率会掉到40帧以下而且伴随着掉帧往往还会出现内容闪烁。这个问题的根子在于RN侧接收到ArkUI的滚动事件后会触发JS层的onScroll回调如果业务代码在onScroll里做了setStateReact会重新渲染整个列表组件而React重新渲染又会驱动新的ArkUI布局形成了一个恶性循环。我的调优方案是RN侧用一个订阅者模式来管理滚动事件。ArkUI的滚动事件先经过一个节流器throttle最小间隔16ms再分发给实际的业务回调。同时所有OnScroll触发的JS操作禁止setState如果业务确实需要根据滚动位置更新UI比如导航栏变色就用ref直接修改原生组件的属性绕开React渲染。帧率问题还跟cell的绘制优先级有关。ArkUI的List支持通过cachedCount设置缓存数量但cachedCount设太大反而会拖慢首屏和内存占用。我建议cachedCount设为视口可显示数量的1.5倍让离屏的cell即使被回收也不会在滚回时因为重新创建而产生掉帧。这部分调优做完后快速滑动的帧率稳定在55~60帧虽然极端场景下还有轻微掉帧但已经不影响正常使用了。5. 实践中的坑从ADB调试到List接口约束的避坑清单写代码的过程是正常流程真正的心酸都在排坑里。这一章列几个我认为最有代表性的坑帮后来人跳过这些弯路。5.1 调试环境的坑adb devices识别不到OpenHarmony设备做OpenHarmony开发第一道坎就是设备调试。我最初用adb devices总是识别不到设备查了一圈原因发现OpenHarmony的调试工具链和Android不完全一样。OpenHarmony设备默认不是通过标准ADB端口通讯的需要先使用hdc工具HarmonyOS Device Connector来连接设备。hdc的启动方式和adb类似但端口和协议不同。所以排查思路是先用hdc list targets确认设备状态不要一上来就死磕adb。另外还有一个坑某些版本的OpenHarmony开发板默认开了USB调试但ADB的调试通道没有开。需要到开发者模式里确认“USB调试”选项是打开的同时确认hdc版本和SDK版本兼容。hdc版本不匹配时连接会显示“device offline”这种问题重新拔插USB接口或者重启hdc服务就能解决。5.2 List数据更新时LazyForEach的key冲突前文提到过LazyForEach的id生成规则必须稳定。这里给一个具体的排查案例我在一个点赞列表里用户点赞后要实时更新对应item的点赞状态。JS侧更新了数组里的一个字段然后调用updateItem方法结果发现列表里的好几条item都串了数据。定位后发现LazyForEach的id生成规则用了index几条item在数据更新时index重新排列了一下导致LazyForEach认为原来的item已经移除了新item又出现了就触发了错误的复用。修复方案很简单把id生成规则改成业务数据的userId问题立刻消失。这里也提醒大家如果业务数据没有唯一主键一定要在数据清洗阶段补一个clientId。否则任何局部刷新、删除、插入操作都可能引发不可预料的渲染错乱。5.3 List接口约束的真坑一次最多渲染多少条ArkUI的List和LazyForEach虽然宣称支持大数据量但并不是无限的。我在测试中发现一次性setData超过2000条数据时List的内存占用会急剧上升滚动也会明显卡顿。这个问题的根源在于LazyForEach虽然只渲染可视区附近的cell但IDataSource内部会维护一个完整的key-index映射表数据越多映射表越大。更麻烦的是当List滚动到接近底部时LazyForEach会把整个映射索引进行一些计算2000条以上的计算量会拖慢帧率。我的方案是给ListContainer强制做一个分页缓存上限列表里最多只保留3000条数据超出部分旧的页面缓存直接丢弃不放进ArkUI的数据源。同时配合虚拟列表的思想如果用户从第1000条往回滑我们重新从JS数据源里补齐前面的数据。这个方案需要JS侧维护一个完整的数据副本但能保证ArkUI侧的渲染始终在一个安全的数据量范围内。5.4 列表项内的RN组件与ArkUI原生组件的触摸事件冲突最后一个坑是触摸事件。cell外层是ArkUI的ListItem内层有RN的Button组件。实际测试时RN的Button点击事件能正常触发但有时候点击偶发失灵而且会带动整个列表滚动。排查后发现是事件冒泡机制的问题。RN侧的触摸事件通过桥接层传递最终和ArkUI的滚动手势识别器产生了竞争。ArkUI基于手势的识别优先级默认情况下滚动手势的优先级更高导致RN的点击手势在快速滑动时被吞掉。修复方案在ArkUI的ListItem上显式设置手势识别优先级让点击手势优先于滚动手势。同时cell上的RN可点击区域要在JS侧加上一个“点击拦截”逻辑在触摸开始到结束的时间内先暂停List的滚动响应触摸结束再恢复。这个坑排查起来很费劲但修好之后对列表整体交互的稳定性提升非常明显强烈建议做RNOpenHarmony混合开发的朋友提前把这个方案落地。6. 后续演进从List到瀑布流再到国际化封装一个List组件只是一个起点。项目的实际需求往往会从垂直列表延伸到瀑布流、多列网格、吸顶分组等更多形态。我在设计之初就考虑到了这一点所以桥接层的接口不光是给List用也给后续的组件预留了扩展空间。6.1 快速扩展一个WaterFlow瀑布流组件ArkUI自带的WaterFlow组件性能和List算是一个量级但API接口完全不同。如果你需要多列瀑布流直接复用ListContainer的数据管理逻辑把渲染层替换成WaterFlow即可。建议把数据管理、状态控制、事件回调这些逻辑抽象成一个useListController的HooksList和瀑布流都从这个Hooks里获取能力这样两个组件共用一套数据流只是UI渲染层不同。后续再加网格列表时也只需要再写一个渲染层。6.2 国际化适配的提前布局列表组件的文案比如“加载更多”“没有更多了”“下拉刷新”在最初设计时就要支持多语言。这部分做晚了后面改起来的成本很高。我的方案是这些内置文案不写在组件内部而是从Bridge配置里下发或者通过props传入业务层根据当前语言模型选择对应的文案。另外一个容易被忽视的点是双向布局。阿拉伯语等从右到左阅读习惯的地区列表的滚动方向和内容排布要和LTR语言保持镜像。ArkUI对RTL布局有内置支持但RN侧的渲染层和样式处理是否兼容还是未知数这部分我目前还没有完整的实践验证先不做结论但建议有出海业务规划的项目在技术选型时就要考虑到这个变量。7. 一些调试技巧和最后的经验总结写到最后分享几个我在实际开发里沉淀下来的调试技巧都是网上比较少提到的细节。技巧一善用hdc的日志过滤。OpenHarmony的hilog调试日志默认输出量很大直接看会被刷屏。我开发时常用hdc shell hilog -t rn_list来过滤RN列表相关的日志或者用hdc shell hilog | grep NativeListModule来只看桥接层的日志。这个习惯能帮你快速定位是JS逻辑出了问题还是桥接层的数据传输出了问题。技巧二在JS侧加一个列表状态的Debug面板。我在ListContainer组件内部埋了一个隐藏的调试开关连续点击标题栏5次会弹出一个半透明面板显示当前数据总量、已经渲染的cell数量、桥接层的调用次数、平均渲染耗时等指标。这个面板在生产包默认关闭但debug包开启后对性能调优的帮助是巨大的很多问题不用上工具就能直观看到。技巧三数据变化时对比ArkUI侧的日志输出时间戳。有时候JS侧的setState已经执行了但UI迟迟不更新。这时可以通过ArkUI侧的渲染日志来定位问题。正常的流程是JS调用桥接方法的时间戳应该和ArkUI侧对应日志的时间戳相差在几毫秒以内。如果差距超过100ms说明数据传输链路有阻塞可能是事件节流策略太激进也可能是ArkUI主线程卡顿。最后打个总结。我个人的体会是React Native和OpenHarmony的跨端方案目前还处于“能跑、要调、别照搬”的阶段。能把一个列表组件做到接近原生体验需要同时理解RN的组件生命周期、ArkUI的渲染机制、以及桥接层的数据传输原理。这篇文章里提到的很多问题只有真机调试时才会遇到模拟器上很难复现。所以如果你也在做类似的事情我的建议是尽早拿到真机尽早把列表页跑起来越早暴露性能问题调整的空间就越大。成本最低的优化永远是在架构阶段做的优化等业务代码堆上来了再重构那才是真的痛。
RELATED

相关推荐

深入解析 ESLint `space-before-keywords` 规则:关键字前置空格的强制规范与 `keyword-spacing` 演进之路

深入解析 ESLint `space-before-keywords` 规则:关键字前置空格的强制规范与 `keyword-spacing` 演进之路

深入解析 ESLint space-before-keywords 规则:关键字前置空格的强制规范与 keyword-spacing 演进之路 【免费下载链接】eslint Find and fix problems in your JavaScript code. 项目地址: https://gitcode.com/GitHub_Trending/es/eslint 关键字&#xff08…

📅 2026/9/12 23:38:45
Crayfish容器引擎:桌面智能体安全运行的核心底座

Crayfish容器引擎:桌面智能体安全运行的核心底座

1. 项目概述:这不是“小龙虾”,而是一套可装进U盘的桌面智能体运行系统 你搜“workbuddy就是小龙虾吗为什么”,点开前十个结果,八成会看到有人把 Crayfish (小龙虾)和 WorkBuddy (工作伙伴…

📅 2026/9/12 23:33:44
SpacetimeDB 订阅语义详解:WebSocket 消息顺序、事务更新与客户端缓存一致性保证

SpacetimeDB 订阅语义详解:WebSocket 消息顺序、事务更新与客户端缓存一致性保证

SpacetimeDB 订阅语义详解:WebSocket 消息顺序、事务更新与客户端缓存一致性保证 【免费下载链接】SpacetimeDB Development at the speed of light 项目地址: https://gitcode.com/GitHub_Trending/sp/SpacetimeDB SpacetimeDB 通过 WebSocket 为客户端提供…

📅 2026/9/12 23:33:44
MORE NEWS

更多资讯

📰

鳑鲏鱼优化算法结合BP神经网络实现分类预测的Matlab源码详解

简介:这份源码包给出了鳑鲏鱼优化算法与BP神经网络结合的分类预测完整实现,面向高校学生在课程设计、期末大作业或毕业设计中的算法仿真场景。压缩包内共十一个文件,其中五个m文件提供主程序、优化算法、适应度函数及混淆矩阵绘制等核心代码&…

📰

改进型YOLOv7实战解析:从结构优化到部署

简介:基于YOLOv7改进的完整实践资料包,面向目标检测方向的研究者、算法工程师及高年级本科生,旨在通过可运行的源码、图像数据与实验报告,帮助读者系统掌握从结构优化、激活函数升级到数据增强的改进路径,并理解训练流…

📰

开源免费、轻量高效的mdput:能否成为Typora的可靠平替

1. 为什么 Typora 用户都在找平替1.1 从 Typora 收费说起Typora 大概是 Markdown 编辑器里知名度最高的那个。它把“所见即所得”做到了极致——左边不用开预览窗口,输入#后面跟个空格,标题样式立刻呈现,打字体验几乎和 Word 一样流畅。2018 …

📰

TDengine 零代码接入 SparkplugB:基于 taosExplorer 的 IIoT 数据同步任务配置指南

TDengine 零代码接入 SparkplugB:基于 taosExplorer 的 IIoT 数据同步任务配置指南 【免费下载链接】TDengine High-performance, scalable time-series database designed for Industrial IoT (IIoT) scenarios 项目地址: https://gitcode.com/GitHub_Trending/t…

📰

mdput评测:一款免费轻量级Markdown编辑器,Typora的替代之选

最近这两周,我把手头的主力Markdown编辑器从Typora换成了mdput,原因很直接:我不想为了一个编辑器去折腾破解激活,也不想在公司和家里两台电脑之间来回对比哪个版本能用。Typora确实是好东西,但从1.0开始收费之后&#…

📰

使用 AI SDK 接入 GMI Cloud:OpenAI 兼容协议下的开源权重模型推理实战

使用 AI SDK 接入 GMI Cloud:OpenAI 兼容协议下的开源权重模型推理实战 【免费下载链接】ai The AI Toolkit for TypeScript. From the creators of Next.js, the AI SDK is a free open-source library for building AI-powered applications and agents 项目地…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬