uni-app 鸿蒙端调 ArkTS 插件,直接传对象快了 43%,可数据一过 2MB 反而更慢

发布时间:2026/7/24 10:45:26
uni-app 鸿蒙端调 ArkTS 插件,直接传对象快了 43%,可数据一过 2MB 反而更慢 先甩结论uni-app 鸿蒙端调 ArkTS 原生插件参数能用对象直传就别用 JSON 字符串裹一层——我在一台 Mate 60 Pro 上跑了 20 组5000 条小数据直接传对象比字符串方案快了 43% 左右。但你别高兴太早数据一过 2MB对象桥的序列化成本直接炸那时候字符串方案反而更稳。下面把两次 benchmark 和根因都摊开说。我当初上原生插件是为了给一个长列表瀑布流做原生渲染加速。官方 List 渲染上万条数据在低端机上掉帧掉得我心里发毛滑两下就白屏一下用户吐槽说像在翻老式相册。我试过懒加载、cachedCount 调参、组件复用效果是好了点但没根治干脆把列表的排版和每条案例的收益计算整个挪到 ArkTS 插件里做uni-app 只负责把数据喂过去。问题就出在喂数据这一步——这玩意儿看着不起眼坑全藏在桥的序列化里文档一个字都没讲明白。我前前后后在这上面卡了差不多一周从怀疑网络、怀疑插件线程一路排到桥的序列化才知道真正的瓶颈根本不在我想的那几个地方。最早我图省事JS 侧先JSON.stringify裹一层丢给插件插件再JSON.parse回来处理处理完又 stringify 回 JS 层。整条链路跑了两趟序列化纯属脱裤子放屁。当时我还自我感觉良好觉得字符串最稳不会有类型对不上的幺蛾子。说白了就是偷懒懒得去研究桥到底怎么搬对象。uni-app 侧两种写法长这样// pages/case-list/case-list.vue —— uni-app 侧两种传参写法constradarPluginuni.requireNativePlugin(RadarCasePlugin)// 方案 AJSON 字符串裹一层functionloadByString(payload){constt0Date.now()conststrJSON.stringify(payload)// 出参序列化constresradarPlugin.loadCasesFromString(str)constlistJSON.parse(res)// 入参反序列化console.log(string 方案耗时,Date.now()-t0,ms)returnlist}// 方案 B直接传对象交给桥自动 marshalingfunctionloadByObject(payload){constt0Date.now()constlistradarPlugin.loadCases(payload)// 桥把 JS 对象转成 ArkTS 对象console.log(object 方案耗时,Date.now()-t0,ms)returnlist}插件侧两个方法一个吃字符串自己解一个直接吃对象// uts/RadarCasePlugin.ets —— ArkTS 原生插件侧 export class RadarCasePlugin { // 方案 A接收字符串自己 JSON.parse loadCasesFromString(raw: string): string { const list JSON.parse(raw) as ArrayCaseItem const out this.enrich(list) return JSON.stringify(out) // 再字符串回去给 JS 层 } // 方案 B接收结构化对象桥已经转好 ArkTS 类型 loadCases(raw: ArrayCaseItem): ArrayCaseItem { return this.enrich(raw) } private enrich(list: ArrayCaseItem): ArrayCaseItem { return list.map(it ({ ...it, score: it.monthlyProfit / it.invest })) } }第一次 benchmark数据量是 5000 条小记录单条约 80 字节总共 400KB 出头。跑出来的数20 组均值单位 ms数据量string 方案object 方案差值5000 条 (~400KB)182103object 快 43%小数据下object 方案省掉的就是那两趟JSON.parse/stringify的冤枉路。说实话我一开始还不信自己手测了三遍才认——这买卖怎么算都亏早该直接传对象。我甚至有点后悔前面那两个项目也都傻乎乎地全程 stringify白白多烧了不少无意义的毫秒。那会儿我还发朋友圈吐槽自己用最贵的写法做最没必要的搬运。后来我把这套对比贴到项目群里组里另一个同事说他之前也踩过只不过他那边是图片列表、体量大所以一开始就用的字符串反而没我这么纠结。我用下面这个脚本各跑了 20 组取均值确认数字不是手抖// 计时脚本两种方案各跑 20 组取均值functionmeasure(fn){consttDate.now();fn();returnDate.now()-t}functionavg(xs){returnxs.reduce((s,n)sn,0)/xs.length}asyncfunctionbench(payload){consta[],b[]for(leti0;i20;i){a.push(measure(()loadByString(payload)))b.push(measure(()loadByObject(payload)))}return{stringAvg:avg(a),objectAvg:avg(b)}}我承认上一节说得太满。把数据量加到 2 万条每条再带一段 base64 缩略图总大小干到 2.3MB再跑一遍结果直接反过来数据量string 方案object 方案2 万条 (~2.3MB)9401680object 方案慢了快一倍。我当时盯着控制台的日志愣了十秒脑子里第一反应是桥抽风了。用上面那个脚本各跑了 20 组两次都卡在 1600ms 往上确认不是偶发。你猜怎么着我把 base64 缩略图去掉、只留纯文本字段object 方案立刻又比字符串快了。说明那堵墙就立在数据体量大这一个点跟字段内容无关。这个发现让我把之前写的几个接口又翻出来复查了一遍果然有两个大数据接口悄悄踩了坑。根因在鸿蒙那套 uts 桥的机制上。对象直传时桥要在 JS 值和 ArkTS 值之间做 deep copy marshaling把每一层都重新建成 ArkTS 对象。打个比方字符串方案像是把一摞文件装进一个箱子搬过去桥只搬箱子对象方案像是把每份文件拆开、逐页复印成鸿蒙格式再搬页越多复印越慢。小对象这步代价可以忽略但 2MB 的嵌套结构一进来CPU 全耗在反复建对象上比你自己JSON.parse还狠。字符串方案反而只占一份连续内存桥只搬一个 string开销是线性的所以到了大数据量级字符串方案反倒更扛造。我后来用 hilog 打了时间戳确认耗时几乎全部发生在桥的 marshaling 阶段插件里的 enrich 计算本身只占零头。也就是说对象越大你付给桥的过路费越高这费还不是固定一笔是跟着数据量往上猛窜。顺便吐槽一句uni-app 文档对桥的序列化机制语焉不详只在某个角落提了句建议小数据直传压根没说大数据的墙在哪、墙多高。我这是自己撞出来的官方那行字跟没说一样。真要较真这套 marshaling 的开销曲线其实值得单独写一篇但目前连个官方性能基准都找不到。阈值我卡在 1.5MB 左右这个数不是拍脑袋。我在 0.5MB、1MB、1.5MB、3MB 四个点都跑过1MB 以内 object 稳赢1.5MB 两边都差不多一过 2MB object 就开始翻车3MB 时 object 已经比 string 慢两倍多。超过阈值就别直传对象了两条路还是用 JSON 字符串稳就是慢点更狠一点把数据落盘成文件只把路径传给插件让 ArkTS 侧用鸿蒙 fs 直接读彻底绕开桥的序列化。// 超过阈值时把数据落盘只传路径asyncfunctionloadHuge(payload){constpath${uni.env.USER_DATA_PATH}/cases_${Date.now()}.jsonawaitwriteFile(path,JSON.stringify(payload))returnradarPlugin.loadCasesFromFile(path)// ArkTS 侧直接 fs 读}// ArkTS 侧从文件读不经过 JS 桥的序列化 loadCasesFromFile(path: string): ArrayCaseItem { const raw fs.readText(path) // 用鸿蒙 fs 读绕开桥 return this.enrich(JSON.parse(raw)) }我现在的写法是按 size 动态选小于 1.5MB 走 object大于就走文件路径。雷达鸭鸿蒙版那个案例瀑布流就是这么干的5000 条一条不差。封装层里我先JSON.stringify量一下长度再决定走哪条分支调用方完全无感。反正从那以后我但凡在 uni-app 鸿蒙端调原生插件第一反应不再是先 stringify 保平安而是先看这坨数据多大。如果让我重来我会一开始就把 size 判断写进封装层而不是等到线上掉帧、用户吐槽才回头补这堂课。说句心里话这套桥的 marshaling 开销曲线挺反直觉的——小数据省事又快的写法大数据下恰恰是最慢的。你那边如果也卡在插件传参的性能上先量一把 size 再决定走哪条路别像我一样傻跑两趟字符串才反应过来。我是老三10 年软件开发经验软件设计师、人工智能应用工程师平时主要折腾鸿蒙 ArkTS 北向开发加 Web 前端也在摸索 AI 自动化。偶尔在 CSDN 写点鸿蒙和 AI 方向的实战笔记。本文遵循 MIT 协议转载请注明出处。

相关新闻

最新新闻

日新闻

周新闻

月新闻