查看: 187|回复: 3

鸿蒙 uni-app x Worker 多线程通信与错误码排障

[复制链接]
发表于 2 小时前 | 显示全部楼层 |阅读模式
uni-app x 在鸿蒙平台可以用 Worker 把耗时任务移出主线程。原文给出的版本边界是:鸿蒙平台从 Worker 4.81 开始支持,Web 4.81 也支持,微信小程序 4.41 支持,iOS 目前不支持。Worker 是真正的多线程,原文特别提醒它与 Android request API 内部使用协程不是一回事。主线程负责 UI 渲染,大量计算留在主线程会卡界面,这是使用 Worker 的直接场景。

一、创建 Worker 与通信模型
API 入口是 uni.createWorker(url: string),传入 Worker 脚本 URL,返回 Worker 对象。主线程侧常用 postMessage(message, options?)、onMessage(callback)、onError(callback) 和 terminate()。其中 terminate() 仅限在主线程调用。Worker 脚本是独立的 .uts 文件,脚本里通过 self 对象与主线程通信:self.onMessage 接收消息,self.postMessage 返回结果,self.env.USER_DATA_PATH 可读取用户数据路径。基础示例如下:
  1. // workers/helloWorkerTask.uts
  2. self.onMessage((message: any) => {
  3.   const data = message as UTSJSONObject
  4.   const value = data['data'] as string
  5.   const num = parseInt(value) || 0
  6.   self.postMessage({ data: (num + 1).toString() })
  7. })
复制代码

主线程创建、监听和发送消息:
  1. const worker = ref<Worker | null>(null)
  2. worker.value = uni.createWorker('workers/helloWorkerTask.uts')
  3. worker.value!.onMessage((message: any) => {
  4.   const data = message as UTSJSONObject
  5.   result.value = (data['data'] as string) || ''
  6. })
  7. worker.value!.onError((error) => {
  8.   console.error('Worker 错误:', error.errCode, error.errMsg)
  9. })
  10. worker.value!.postMessage({ data: inputValue.value, needReply: true })
  11. // 页面卸载时
  12. worker.value!.terminate()
复制代码

这里要守住两条边界:UI 操作必须在主线程,子线程不能操作 DOM API,也不能操作绑定在界面上的响应式变量;共享变量需要线程安全,避免多个线程同时写同一个变量,或一个线程读、另一个线程在写。

二、耗时计算、JSON 处理与并行
大量计算是最典型的落点。把循环放到 Worker 脚本里,主线程只负责创建、发送参数和接收结果:
  1. self.onMessage((message: any) => {
  2.   const data = message as UTSJSONObject
  3.   const count = (data['count'] as number) || 1000000
  4.   let sum = 0
  5.   for (let i = 1; i <= count; i++) {
  6.     sum += i
  7.   }
  8.   self.postMessage({ result: sum, count: count })
  9. })
复制代码

主线程在 onMessage 里读取 result,拿到结果后调用 terminate() 结束该 Worker。JSON 数据处理同理:Worker 接收 JSON 字符串,解析后按 status 过滤 active 项,再通过 self.postMessage 返回总数、过滤后数量和序列化数据。多个 Worker 并行时,可以用 completedCount 统计完成数量,全部完成后统一处理结果。但原文明确提醒不要开太多线程,CPU 核数有限,线程开太多反而影响性能。

三、鸿蒙 Sendable 共享变量
鸿蒙平台提供了 Sendable 协议,可通过 harmonySendable 选项实现共享变量。原文指出,这种方式的性能比普通 postMessage 好很多,适合在鸿蒙侧传递较大数据或共享变量的场景。调用时在 postMessage 的第二个参数中传入选项:
  1. worker.postMessage({ data: 'large data' }, { harmonySendable: true })
复制代码

使用共享变量时仍要回到线程安全:避免多线程同时写同一个变量,或一个线程读、另一个线程在写。Sendable 是性能手段,不是绕过线程安全约束的理由。

四、错误码排障与生命周期
Worker 运行时错误通过 onError 监听。原文给出的错误码包括:5000501 表示 Worker 运行错误,5000504 表示 Worker 线程中不支持调用的 API,5000506 表示 Worker 文件路径无效,5000505 表示 Worker 线程初始化失败。排障时先看 errCode 和 errMsg,再核对 Worker 脚本路径、是否在子线程调用了不支持的 API,以及 Worker 线程初始化条件。示例:
  1. worker.onError((error) => {
  2.   if (error.errCode == 5000501) {
  3.     console.log('Worker 运行错误')
  4.   } else if (error.errCode == 5000504) {
  5.     console.log('Worker 线程中不支持调用的 API')
  6.   } else if (error.errCode == 5000506) {
  7.     console.log('Worker 文件路径无效')
  8.   } else if (error.errCode == 5000505) {
  9.     console.log('Worker 线程初始化失败')
  10.   }
  11. })
复制代码

生命周期上,页面卸载时要 terminate() 并清空 Worker 引用,创建前也要防重复创建。Worker 脚本内还可通过 self.env.USER_DATA_PATH 访问用户数据路径,用于文件相关操作。

五、实践取舍与验证
跨端项目要先看支持范围:iOS 目前不支持 Worker,原文没有给出替代实现,工程上需要按平台能力做评估。验证时重点覆盖基础通信、耗时计算、JSON 过滤、多 Worker 并行完成计数和错误码分支;观察主线程是否仍能响应、onMessage 是否拿到预期结果、onError 是否命中对应错误码、页面卸载后 Worker 是否已销毁。架构上不要把 Worker 当成越多越好,按任务拆分、按核数控制并发,耗时任务放子线程,UI 和响应式变量操作留在主线程。

原文的核心结论很明确:uni-app x 在鸿蒙上用 Worker 解决主线程卡顿,关键不是会调 createWorker,而是把通信、Sendable、错误码和销毁时机一起设计好。
回复

使用道具 举报

发表于 2 小时前 | 显示全部楼层

Re: 鸿蒙 uni-app x Worker 多线程通信与错误码排障

楼主这篇整理得很实用,把 Worker 的创建、通信、生命周期和错误码都串起来了。版本边界和 terminate 只能在主线程调用这两个点很关键,另外子线程不能操作界面响应式变量、共享变量要注意线程安全也提醒得很到位。Sendable 那个性能优化思路对鸿蒙侧传大数据挺有价值,但确实不能拿它绕过线程安全。排障部分按 errCode 对照路径、不支持的 API 和初始化条件,思路很清楚。实际项目里我会再注意页面卸载时 terminate 并清空引用、创建前防重复,以及并行 Worker 数量别开太多。跨端项目里 iOS 目前不支持 Worker 这点也要提前考虑降级方案,避免上线后才发现。
回复 支持 反对

使用道具 举报

发表于 2 小时前 | 显示全部楼层

Re: 鸿蒙 uni-app x Worker 多线程通信与错误码排障

这篇总结得很清楚,尤其是版本边界和错误码部分,正好解决了我在鸿蒙上排查 Worker 时的几个疑惑。之前只知道耗时任务要挪出主线程,但对 terminate 只能在主线程调用、Worker 脚本里用 self 通信这些细节没有系统梳理过。Sendable 那段也有收获,原来 harmonySendable 在传较大数据时性能会比普通 postMessage 好不少,不过线程安全的约束还是不能放松,这点提醒得很到位。 实践上我觉得生命周期这块最容易出问题,页面卸载不 terminate 或者重复创建,后面很容易出现资源残留和消息错乱。另外错误码 5000506 文件路径无效也很常见,Worker 脚本的 URL 写法在不同工程结构下需要多验证几次。iOS 目前不支持这一点也提醒得好,跨端项目里得提前设计降级方案,不能把核心逻辑全押在 Worker 上。 感谢整理,准备按这个思路把现有项目里的计算任务拆一版试试。
回复 支持 反对

使用道具 举报

发表于 2 小时前 | 显示全部楼层

Re: 鸿蒙 uni-app x Worker 多线程通信与错误码排障

楼主整理得挺清楚,尤其把 Worker 和协程的区别、UI 必须留在主线程、子线程不能碰响应式变量和 DOM 这些边界讲明白了。版本支持范围先确认也很关键,iOS 目前不支持,跨端项目就不能把核心逻辑强依赖 Worker。错误码排障那段很实用,先看 errCode 和 errMsg,再核对脚本路径、子线程是否调用了不支持的 API、线程初始化条件,顺序比较合理。Sendable 能提升大数据传递性能这一点也有价值,但确实不能拿它绕过线程安全。生命周期上页面卸载 terminate 并清空引用、创建前防重复,以及不要开太多线程,都是实际容易踩坑的地方。整体对鸿蒙 uni-app x 里落地多线程任务很有参考意义。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

指导单位

江苏省公安厅

江苏省通信管理局

浙江省台州刑侦支队

DEFCON GROUP 86025

Hacking Group 021A

旗下站点

态势感知中心

应急响应中心

红盟安全

联系我们

官方QQ群:112851260

官方邮箱:security#ihonker.org(#改成@)

官方核心成员

关注微信公众号

Archiver|手机版|小黑屋| ( 沪ICP备2021026908号 )

GMT+8, 2026-10-30 05:43 , Processed in 0.124481 second(s), 28 queries , Gzip On.

Powered by ihonker.com

Copyright © 2015-现在.

  • 返回顶部