《解压Zip文件》二、启动一个Worker指南

发布时间:2026/7/23 0:22:53
《解压Zip文件》二、启动一个Worker指南 HarmonyOS ohos.worker (启动一个Worker) 使用指南多线程实战详解模块类型系统内置模块关键词Worker、多线程、后台任务、线程通信、ArkTS效果一、为什么需要 Worker在 HarmonyOS 应用中主线程UI 线程负责界面渲染和用户交互。当执行耗时操作如大文件解压、复杂计算、数据解析时主线程会被阻塞导致界面卡顿甚至 ANR应用无响应。ohos.worker模块提供了多线程能力允许开发者将耗时任务放到独立的 Worker 线程中执行主线程保持流畅。工作原理图┌─────────────────┐ postMessage() ┌─────────────────┐ │ │ ─────────────────────► │ │ │ 主线程 (UI) │ │ Worker 线程 │ │ │ ◄───────────────────── │ (后台执行) │ └─────────────────┘ onmessage └─────────────────┘ │ 负责UI 渲染 │ 负责耗时任务 │ 用户交互 │ 文件操作 │ 事件处理 │ 数据计算线程通信模型Worker 线程与主线程之间通过消息机制进行通信主线程通过postMessage()向 Worker 发送数据Worker 线程通过workerPort.postMessage()向主线程返回结果双方通过onmessage回调接收对方的消息二、核心 API 一览2.1 主线程侧 APIimportworker,{MessageEvents}fromohos.worker;方法/属性说明new worker.ThreadWorker(scriptPath)创建 Worker 线程实例worker.postMessage(data)向 Worker 线程发送消息worker.onmessage接收 Worker 线程返回的消息worker.onmessageerror接收反序列化失败的消息worker.onerror接收 Worker 线程异常事件worker.terminate()销毁 Worker 线程释放资源2.2 Worker 线程侧 APIimport{MessageEvents,ErrorEvent,ThreadWorkerGlobalScope,worker}fromkit.ArkTS;方法/属性说明worker.workerPort获取 Worker 线程的全局作用域workerPort.postMessage(data)向主线程发送消息workerPort.onmessage接收主线程发来的消息workerPort.onmessageerror接收反序列化失败的消息workerPort.onerror接收 Worker 运行异常workerPort.close()关闭 Worker 线程线程内部调用三、完整实战示例3.1 场景后台执行文件解压本示例演示一个完整的 Worker 使用流程主线程发起解压请求Worker 在后台执行解压完成后通知主线程。3.2 步骤一配置 Worker 入口在entry/build-profile.json5中声明 Worker 文件路径{ apiType: stageMode, buildOption: { sourceOption: { workers: [ ./src/main/ets/workers/UnzipWorker.ets ] } } }重要必须在build-profile.json5中注册 Worker 文件否则编译时不会打包该文件运行时会报错找不到脚本。3.3 步骤二编写 Worker 线程代码文件路径entry/src/main/ets/workers/UnzipWorker.etsimport{ErrorEvent,MessageEvents,ThreadWorkerGlobalScope,worker}fromkit.ArkTS;importzlibfromohos.zlib;import{BusinessError}fromohos.base;import{hilog}fromkit.PerformanceAnalysisKit;constTAGUnzipWorker;// ✅ 定义消息协议接口避免 any 类型错误interfaceWorkerRequest{zipPath:string;extractPath:string;taskId:number;}// 获取 Worker 线程的全局通信端口constworkerPort:ThreadWorkerGlobalScopeworker.workerPort;// 监听主线程发来的消息workerPort.onmessage(e:MessageEvents){// ✅ 必须显式类型转换ArkTS 禁止使用隐式 anyconstdata:WorkerRequeste.dataasWorkerRequest;constzipPath:stringdata.zipPath;constextractPath:stringdata.extractPath;consttaskId:numberdata.taskId;hilog.info(0x0001,TAG,收到解压任务:${zipPath});constoptions:zlib.Options{level:zlib.CompressLevel.COMPRESS_LEVEL_DEFAULT_COMPRESSION};try{zlib.decompressFile(zipPath,extractPath,options,(err:BusinessError){if(err!nullerr.code!0){// 解压失败通知主线程workerPort.postMessage({taskId:taskId,status:error,message:解压失败:${err.message}});}else{// 解压成功通知主线程workerPort.postMessage({taskId:taskId,status:success,message:解压完成});}});}catch(err){constbizErrerrasBusinessError;workerPort.postMessage({taskId:taskId,status:error,message:异常:${bizErr.message}});}};// 监听消息反序列化错误workerPort.onmessageerror(e:MessageEvents){hilog.error(0x0001,TAG,消息反序列化失败);};// 监听 Worker 运行异常workerPort.onerror(e:ErrorEvent){hilog.error(0x0001,TAG,Worker 异常:${e.message});};3.4 步骤三在主线程中使用 Workerimportworker,{MessageEvents}fromohos.worker;import{PromptAction}fromkit.ArkUI;import{Context}fromkit.AbilityKit;interfaceUnzipResult{taskId:number;status:success|error;message:string;}functionstartUnzipInWorker(context:Context,zipPath:string,extractPath:string,promptAction:PromptAction):void{// 1. 创建 Worker 实例路径相对于 entry/src/main/ets/constunzipWorkernewworker.ThreadWorker(entry/ets/workers/UnzipWorker.ets);// 2. 监听 Worker 返回的消息unzipWorker.onmessage(e:MessageEvents):void{constresulte.dataasUnzipResult;if(result.statussuccess){promptAction.showToast({message:result.message});}else{promptAction.showToast({message:result.message});}// 3. 使用完毕后销毁 Worker释放资源unzipWorker.terminate();};// 3. 监听 Worker 异常unzipWorker.onerror(e:ErrorEvent):void{promptAction.showToast({message:Worker 错误:${e.message}});unzipWorker.terminate();};// 4. 向 Worker 发送解压任务unzipWorker.postMessage({zipPath:zipPath,extractPath:extractPath,taskId:Date.now()});}四、消息传递的数据类型Worker 线程与主线程之间传递的数据通过结构化克隆算法进行序列化支持以下类型支持的类型示例基本类型string、number、boolean、null、undefined对象与数组{ name: test }、[1, 2, 3]ArrayBuffer二进制数据传输Map / Set集合类型Date / RegExp内置对象不支持的类型会抛出序列化异常函数FunctionDOM 节点SymbolWeakMap / WeakSet包含循环引用的对象五、Worker 生命周期管理5.1 创建阶段constmyWorkernewworker.ThreadWorker(entry/ets/workers/MyWorker.ets);创建时传入的路径格式为{moduleName}/ets/workers/{fileName}.ets5.2 运行阶段// 发送消息myWorker.postMessage({action:start,payload:data});// 接收消息myWorker.onmessage(e:MessageEvents){/* 处理结果 */};5.3 销毁阶段// 主线程销毁 WorkermyWorker.terminate();// Worker 线程自行关闭在 Worker 内部调用workerPort.close();最佳实践Worker 使用完毕后务必调用terminate()销毁否则线程会持续占用系统资源。六、最佳实践6.1 何时使用 Worker适合使用 Worker不适合使用 Worker文件压缩/解压简单的数据赋值大文件读写UI 状态更新图片处理/编码路由导航复杂数据计算快速同步操作JSON 大文件解析事件监听注册6.2 错误处理规范// ✅ 推荐完整的错误处理链myWorker.onmessage(e:MessageEvents){constresulte.dataasTaskResult;if(result.statuserror){// 处理业务错误}myWorker.terminate();// 确保销毁};myWorker.onerror(e:ErrorEvent){// 处理线程异常myWorker.terminate();};6.3 多 Worker 管理如果需要同时处理多个任务可以创建多个 Worker 实例// 并行解压多个文件for(constzipFileofzipFiles){constwnewworker.ThreadWorker(entry/ets/workers/UnzipWorker.ets);w.onmessage(e:MessageEvents){// 处理各自的结果w.terminate();};w.postMessage({zipPath:zipFile.path,extractPath:zipFile.out});}七、常见问题Q1Worker 文件找不到确保已在build-profile.json5的sourceOption.workers中注册路径。Q2postMessage 报错 “DataCloneError”检查传递的数据是否包含不支持的类型如函数、Symbol 等。Q3Worker 中能否访问 UI不能。Worker 线程无法操作 UI 组件只能通过消息将结果传回主线程由主线程更新 UI。Q4Worker 中能否使用 async/await可以。Worker 线程支持异步操作但需注意 Worker 的生命周期管理。Q5报错 “Use explicit types instead of any, unknown” (arkts-no-any-unknown)这是 ArkTS 的严格类型检查规则。MessageEvents的data属性返回类型为隐式any在 ArkTS 中必须显式声明类型// ❌ 错误隐式 anyworkerPort.onmessage(e:MessageEvents){constdatae.data;// 编译报错 arkts-no-any-unknownconstpathdata.zipPath;};// ✅ 正确定义接口 显式类型转换interfaceWorkerRequest{zipPath:string;extractPath:string;}workerPort.onmessage(e:MessageEvents){constdata:WorkerRequeste.dataasWorkerRequest;// 显式类型constpath:stringdata.zipPath;};经验提示主线程接收 Worker 消息时同样需要显式类型转换如const resp e.data as WorkerResponse;