一、背景
在鸿蒙开发中提供了两种多线程并发方案,分别是TaskPool与Worker,此篇文章主要总结下Worker
二、Worker概念
1、Worker为应用程序提供一个多线程的运行环境,实现后台线程与宿主线程分离
2、Worker有自己的生命周期,一旦创建不会主动销毁,需手动销毁空闲的Worker
3、作用:在后台线程中处理耗时操作(如:计算密集型或高延迟任务),避免影响主线程(如:UI主线程)
4、目标:将「重量级、长期、有状态」的耗时逻辑从主线程剥离,解决主线程被阻塞导致 UI 无响应的问题
5、运作机制
Worker子线程和宿主线程通过消息传递机制通信,利用序列化、引用传递或转移所有权的机制完成命令和数据的交互

三、注意事项
1、创建Worker
A、自动创建:使用DevEco Studio 单击鼠标右键 > New > Worker,一键生成Worker的模板文件及配置信息
B、手动创建:在工程目录下创建Worker文件,并在build-profile.json5配置Worker文件路径
TypeScript
//Stage模型:
"buildOption": {
"sourceOption": {
"workers": [
"./src/main/ets/workers/worker.ets"
]
}
}
2、文件路径
A、Stage模型--->路径规则:{moduleName}/ets/{relativePath}
TypeScript
1. // worker线程文件所在路径:"entry/src/main/ets/workers/worker.ets"
2. const workerStage1: worker.ThreadWorker = new worker.ThreadWorker('entry/ets/workers/worker.ets');
B、HAR包中加载Worker线程文件--->路径规则:@{moduleName}/ets/{relativePath}
TypeScript
1. // @标识路径加载形式:
2. // worker线程文件所在路径: "har/src/main/ets/workers/worker.ets"
3. const workerStage4: worker.ThreadWorker = new worker.ThreadWorker('@har/ets/workers/worker.ets');
3、资源加载
A、同时运行的Worker子线程数量最多为64个(与napi_create_ark_runtime创建的runtime总数不超过80)
B、单次序列化传输的数据量大小限制为16MB
4、模块使用限制
A、只能使用线程安全的库,UI相关的非线程安全库不能使用
B、不支持在多个HAP之间共享使用相同的Worker线程文件
C、不支持在Worker工作线程中AppStorage
D、禁止使用export语法导出
5、异常处理
A、API 18+使用onAllErrors回调捕获异常,Worker线程继续存活
B、API 18以前使用onerror回调捕获异常,Worker线程进入销毁流程,无法继续使用
四、Worker生命周期
生命周期顺序:创建--->运行--->销毁
1、创建阶段
在主线程或父Worker线程中,调用new worker.ThreadWorker(scriptURL)
2、运行阶段
通过 postMessage 和 onmessage 与创建它的线程进行双向通信。
-
核心方法:
-
parentPort.postMessage(): 发送消息。 -
parentPort.onmessage(): 接收消息。 -
onerror(): 处理错误。
-
3、销毁阶段
由创建该Worker的线程(父线程)主动调用 worker.terminate()
-
terminate():立即终止 -
close():正常关闭
**关键点:**必须手动触发。对于多级Worker,必须严格遵循 "从子到父"的销毁顺序(即先销毁所有子Worker,再销毁父Worker)
五、怎么用
步骤1:配置构建文件
这一步是保证系统能找到新建的Worker脚本
打开 entry/build-profile.json5 文件,在 buildOption 字段内添加 sourceOption 配置:

步骤2:创建Worker后台脚本
在 entry/src/main/ets/ 目录下,创建 workers 文件夹并创建脚本文件
TypeScript
import { MessageEvents, worker,ErrorEvent } from '@kit.ArkTS';
// 1. 获取通信端口
const parentPort = worker.workerPort;
// 2. 监听主线程发来的消息 - 使用正确的MessageEvent类型
parentPort.onmessage = (e: MessageEvents) => {
console.log('[Worker] 收到数据: ' + e.data);
// 3. 执行耗时计算 (例如计算斐波那契数列)
const n: number = e.data;
const result = fibonacci(n);
// 4. 将结果发送回主线程
console.log('[Worker] 计算完成,结果: ' + result);
parentPort.postMessage(result);
};
// 一个模拟的耗时计算函数
function fibonacci(n: number): number {
if (n <= 1) return n;
// 注意:递归版本对较大n值会很慢,这里为演示用
return fibonacci(n - 1) + fibonacci(n - 2);
}
// 5. 使用正确的ErrorEvent类型处理错误
parentPort.onerror = (ev: ErrorEvent): void => {
console.error('[Worker] 发生错误: ' + ev.message);
};
步骤3:创建主页面调用Worker
TypeScript
import { ErrorEvent, MessageEvents, worker } from '@kit.ArkTS';
@Entry
@Component
struct Index {
@State result: string = '等待计算';
@State isCalculating: boolean = false;
private calcWorker?: worker.ThreadWorker
build() {
Column({ space: 20 }) {
Text('Worker演示')
.fontSize(30)
.fontWeight(FontWeight.Bold)
.margin({ bottom: 30 })
Text(this.result)
.fontSize(24)
.fontColor(this.isCalculating ? Color.Red : Color.Black)
.margin({ bottom: 20 })
Button(this.isCalculating ? '计算中...' : '开始计算')
.width('80%')
.height(50)
.fontSize(18)
.backgroundColor(this.isCalculating ? Color.Gray : Color.Blue)
.enabled(!this.isCalculating)
.onClick(() => {
this.startCalculation();
})
Button('终止Worker')
.width('80%')
.height(50)
.fontSize(18)
.backgroundColor(Color.Orange)
.onClick(() => {
this.terminateWorker();
})
// 显示进度或状态
if (this.isCalculating) {
LoadingProgress()
.width(50)
.height(50)
.margin({ top: 20 })
}
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
.padding(20)
}
// 启动Worker计算
startCalculation() {
// 1. 先清理可能存在的旧Worker
this.terminateWorker();
// 2. 更新UI状态
this.isCalculating = true;
this.result = '正在创建Worker...';
console.log('[UI] 开始计算流程');
try {
// 3. 创建Worker实例
this.calcWorker = new worker.ThreadWorker('entry/ets/worker/DataSyncWorker.ets');
console.log('[UI] Worker创建成功');
// 4. 设置Worker回调
this.calcWorker.onmessage = (e: MessageEvents): void => {
console.log('[UI] 收到Worker结果: ' + e.data);
this.result = '计算结果: ' + e.data;
this.isCalculating = false;
// 计算完成后可以立即销毁Worker,或者保留以备后用
this.terminateWorker();
};
this.calcWorker.onerror = (ev: ErrorEvent): void => {
console.error('[UI] Worker发生错误: ' + ev.message);
this.result = '错误: ' + ev.message;
this.isCalculating = false;
};
// 5. 更新状态并发送计算任务
this.result = '计算中...';
console.log('[UI] 向Worker发送计算任务');
// 计算斐波那契数列第30项(比35项快,适合演示)
const calculateTarget = 30;
this.calcWorker.postMessage(calculateTarget);
} catch (error) {
console.log('lucy== error',JSON.stringify(error))
console.error('[UI] 创建Worker失败: ' + error.message);
this.result = '创建Worker失败';
this.isCalculating = false;
}
}
// 终止Worker
terminateWorker() {
if (this.calcWorker) {
try {
this.calcWorker.terminate(); // 直接终止Worker,释放资源
console.log('lucy== 终止成功')
console.log('[UI] Worker已成功终止');
} catch (err) {
console.log('lucy== 终止失败',JSON.stringify(err))
console.error('[UI] 终止Worker失败: ' + JSON.stringify(err));
}
this.calcWorker = undefined; // 清空实例引用,避免内存泄漏和误操作
}
}
// 页面生命周期:离开时清理Worker
aboutToDisappear(): void {
console.log('[UI] 页面即将销毁,清理Worker');
this.terminateWorker();
}
}
六、适用场景
A、长耗时任务:执行时间 > 10秒(如大插件解压)
B、长期运行的后台服务(如音乐播放器、实时定位追踪)
C、频繁双向通信(如实时聊天的消息处理)
D、需指定专属线程(避免切换、绑定特性)