
简体中文
现代CPU都是多核的。主线程的代码是运行在CPU的主核上的。可以通过 worker api来利用其他核并行计算,加快运算速度。
uni-app x的代码,默认都是在主线程执行的,主线程也称为UI线程。
当需要使用子线程能力时,可以通过本API操作。
当然本API只是一种跨端封装,并且为了跨端还约束了一些写法。开发者也可以在uts插件中自行使用纯原生代码来操作线程。
注意:
常见场景:
创建一个Worker对象
Web | 微信小程序 | Android | Android uni-app x UTS 插件 | iOS | iOS uni-app x UTS 插件 | HarmonyOS | HarmonyOS uni-app x UTS 插件 |
---|---|---|---|---|---|---|---|
4.81 | 4.41 | 4.81 | 4.81 | x | 4.81 | 4.81 | 4.81 |
名称 | 类型 | 必填 | 默认值 | 兼容性 | 描述 |
---|---|---|---|---|---|
url | string | 是 | - | Worker脚本的URL |
类型 | ||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Worker | ||||||||||||||||||||||||||||||
|
onMessage 监听主线程/Worker 线程向当前线程发送的消息的事件。
Web | 微信小程序 | Android | iOS | HarmonyOS |
---|---|---|---|---|
- | 4.41 | - | x | - |
名称 | 类型 | 必填 | 默认值 | 兼容性 | 描述 |
---|---|---|---|---|---|
callback | (message: any) => void | 是 | - |
onError 监听 Worker 线程错误事件。当 Worker 线程中发生脚本错误时会触发此事件。
Web | 微信小程序 | Android | iOS | HarmonyOS |
---|---|---|---|---|
- | 4.41 | - | x | - |
名称 | 类型 | 必填 | 默认值 | 兼容性 | 描述 |
---|---|---|---|---|---|
callback | (result: WorkerOnErrorCallbackResult) => void | 是 | - |
名称 | 类型 | 必备 | 默认值 | 兼容性 | 描述 | |||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
errCode | number | 是 | - | |||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||
errSubject | string | 是 | - | 统一错误主题(模块)名称 | ||||||||||||||||||||||||||||
data | any | 否 | - | 错误信息中包含的数据 | ||||||||||||||||||||||||||||
cause | Error | 否 | - | 源错误信息,可以包含多个错误,详见SourceError | ||||||||||||||||||||||||||||
errMsg | string | 是 | - |
postMessage 向主线程/Worker 线程发送的消息。
Web | 微信小程序 | Android | iOS | HarmonyOS |
---|---|---|---|---|
- | 4.41 | - | x | - |
名称 | 类型 | 必填 | 默认值 | 兼容性 | 描述 | ||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
message | any | 是 | - | ||||||||||||||||||||
options | WorkerPostMessageOptions | 否 | - | ||||||||||||||||||||
|
terminate 结束当前 Worker 线程。仅限在主线程 worker 对象上调用。
Web | 微信小程序 | Android | iOS | HarmonyOS |
---|---|---|---|---|
- | 4.41 | - | x | - |
示例为hello uni-app x alpha分支,与最新HBuilderX Alpha版同步。与最新正式版同步的master分支示例另见
示例
<template>
<scroll-view class="container">
<view class="status-section">
<text class="status-label">Worker状态: </text>
<text class="status-text">{{statusText}}</text>
</view>
<view class="button-group">
<text class="description-text">操作步骤:1.创建Worker 2.添加消息监听 3.发送数据测试</text>
<button class="btn" type="primary" :disabled="created_boolean" @click="create">创建Worker</button>
<button class="btn" type="primary" @click="onWorkerMsg">添加消息监听</button>
<button class="btn" type="primary" @click="onWorkerError">添加错误监听</button>
<button class="btn" @click="destory" :disabled="workerStatus != 'created'">销毁Worker</button>
</view>
<view class="input-section">
<text class="section-title">输入测试值:</text>
<text class="description-text">点击发送按钮后,会将输入值传给WorkerTask,在子线程执行+1操作后返回结果</text>
<input class="input-field" v-model="inputValue" type="number" placeholder="请输入数字" />
<button class="btn" type="primary" @click="sendMessage" :disabled="workerStatus != 'created'">发送到WorkerTask (值+1)</button>
</view>
<view class="log-section">
<text class="section-title">通信日志:</text>
<scroll-view class="log-container" scroll-y="true">
<view v-for="(log, index) in logs" :key="index" class="log-item">
<text :class="['log-text', log.type]">{{log.message}}</text>
</view>
</scroll-view>
<button @click="clearLogs" class="btn clear-btn">清空日志</button>
</view>
<!-- #ifdef APP-HARMONY || WEB -->
<view class="uni-btn-v">
<navigator url="/pages/API/create-worker/worker-sendable-transfer">
<button type="primary">worker sendable transfer 示例</button>
</navigator>
</view>
<!-- #endif -->
</scroll-view>
</template>
<script>
export default {
onUnload() {
this.destory();
},
data() {
return {
created_boolean: false,
workerStatus: 'none', // none, created, destroyed
isListening: false,
logs: [] as Array<UTSJSONObject>,
inputValue: '1', // 默认值为1
taskResult: '',
worker: null as Worker | null
}
},
computed: {
statusText() : string {
switch (this.workerStatus) {
case 'none': return '未创建';
case 'created': return '已创建';
case 'destroyed': return '已销毁';
default: return '未知';
}
}
},
methods: {
// 添加日志方法
addLog(message : string, type : string = 'info') {
const now = new Date();
const timeStr = `${now.getHours().toString().padStart(2, '0')}:${now.getMinutes().toString().padStart(2, '0')}:${now.getSeconds().toString().padStart(2, '0')}`;
const logItem = {
message: `[${timeStr}] ${message}`,
type: type,
time: timeStr
} as UTSJSONObject;
this.logs.unshift(logItem);
// 限制日志数量
if (this.logs.length > 50) {
this.logs = this.logs.slice(0, 50);
}
},
// 创建Worker
create() {
this.worker = uni.createWorker('workers/helloWorkerTask.uts');
this.workerStatus = 'created';
this.addLog('Worker创建成功', 'success');
this.created_boolean = true;
},
onWorkerMsg() {
if (this.worker == null) {
this.addLog('请先创建worker', 'warning');
return;
}
this.worker!.onMessage((result) => {
// 处理Worker返回的消息
console.log(`收到Worker消息:`, result);
const res = result as UTSJSONObject;
const resultData = res['data'] as string;
this.taskResult = resultData;
this.inputValue = this.taskResult
this.addLog(`收到WorkerTask返回: ${resultData}`, 'receive');
})
},
onWorkerError() {
if (this.worker == null) {
this.addLog('请先创建worker', 'warning');
return;
}
this.worker!.onError((error) => {
console.error('Worker发生错误:', error);
// this.addLog(`Worker错误: ${error.message}`, 'error');
})
},
// 向workerTask发送消息
sendMessage() {
// 检查输入值
if (this.inputValue == '') {
this.addLog('请输入有效的数字', 'warning');
return;
}
const options = {
data: this.inputValue,
needReply: true
};
this.worker!.postMessage(options, null);
this.addLog(`发送值到WorkerTask: ${this.inputValue}`, 'send');
},
// 销毁Worker
destory() {
if (this.worker == null) {
this.addLog('没有创建worker,无法销毁', 'warning');
return;
}
this.worker!.terminate();
this.workerStatus = 'destroyed';
this.isListening = false;
this.addLog('Worker已销毁', 'warning');
this.created_boolean = false;
},
// 清空日志
clearLogs() {
this.logs = [];
},
test_resetInputValue() {
this.inputValue = '1'
},
}
}
</script>
<style>
.container {
flex: 1;
padding: 10px;
}
.status-section {
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 20px;
padding: 10px;
background-color: #ffffff;
border-radius: 8px;
}
.status-label {
font-size: 16px;
color: #666666;
}
.status-text {
font-size: 16px;
font-weight: bold;
margin-left: 8px;
}
.button-group {
flex-direction: column;
margin-bottom: 10px;
}
.input-section {
margin-bottom: 20px;
padding: 15px;
background-color: #ffffff;
border-radius: 8px;
}
.input-field {
/* #ifdef MP-WEIXIN */
height: 3em;
/* #endif */
width: 100%;
padding: 12px;
border: 1px solid #dddddd;
border-radius: 6px;
font-size: 16px;
margin: 10px 0;
background-color: #ffffff;
}
.btn {
/* height: 50px; */
margin-bottom: 10px;
padding: 5px 10px;
border-radius: 6px;
font-size: 14px;
text-align: center;
}
.log-section {
background-color: #ffffff;
border-radius: 8px;
padding: 15px;
}
.section-title {
font-size: 18px;
font-weight: bold;
color: #333333;
margin-bottom: 10px;
}
.log-container {
height: 300px;
border: 1px solid #dddddd;
border-radius: 4px;
padding: 10px;
margin: 10px 0;
background-color: #fafafa;
}
.log-item {
margin-bottom: 5px;
}
.log-text {
font-size: 12px;
line-height: 1.4;
}
.log-text.info {
color: #2196F3;
}
.log-text.success {
color: #4CAF50;
}
.log-text.warning {
color: #ff9800;
}
.log-text.error {
color: #f44336;
}
.log-text.send {
color: #9C27B0;
}
.log-text.receive {
color: #009688;
}
.clear-btn {
background-color: #ff9800;
font-size: 12px;
padding: 8px 12px;
color: #ffffff;
border-radius: 4px;
text-align: center;
}
.description-text {
font-size: 14px;
color: #666666;
line-height: 1.4;
margin-bottom: 10px;
}
</style>
名称 | 类型 | 必备 | 默认值 | 兼容性 | 描述 |
---|---|---|---|---|---|
errMsg | string | 是 | - | 错误信息 |
worker 代码,是独立的 uts
文件,所有worker代码文件需要放置在专门的目录。在项目的 manifest.json
中可配置 Worker 文件放置的目录:
{
//...
"workers": {
"path": "workers", // 相对于项目根目录。此配置的意思是在项目根目录下的workers目录下存放worker代码。
"isSubpackage": true // 是否分包,默认为 false(仅微信小程序有效)
}
}
如果不使用微信小程序的分包配置,也可以使用简写配置:
{
//...
"workers" : "workers"
}
参考上一步的配置,在项目根目录下创建 workers
目录,并创建示例 HelloWorkerTask.uts
文件如下:
├─ static
├─ workers // Worker 目录
│ └─ HelloWorkerTask.uts // Worker 代码文件
├─ App.uvue
├─ main.uts
├─ manifest.json
└─ pages.json
Worker 代码中需定义一个类并继承自基类 WorkerTaskImpl
,重写 onMessage
方法接收主线程发送的数据。
以下是 HelloWorkerTask.uts
示例代码:
/**
* HelloWorkerTask
*/
export class HelloWorkerTask extends WorkerTaskImpl {
/**
* 构造函数
*/
constructor() {
super();
//初始化操作
// console.log("构造器初始化");
}
/**
* 实现入口函数
*/
override entry() {
//入口函数,Worker 启动时执行
// console.log("启动完成,等待主线程消息");
}
/**
* 实现接收主线程发送的消息
*/
override onMessage(message : any) {
// 处理消息对象
const messageData = message as UTSJSONObject;
// console.log('收到主线程数据:', messageData);
// 发送消息给主线程
this.postMessageToMain();
}
/**
* 回复消息
*/
private postMessageToMain() {
const response = {
msg: 'message send by worker!'
};
// 调用 postMessage 发送消息给主线程
this.postMessage(response);
}
}
其中 WorkerTaskImpl
基类定义如下:
/**
* WorkerTaskImpl
*/
export class WorkerTaskImpl {
/**
* 入口函数
* 可重写修改
*/
override entry():void;
/**
* 接收主线程发送的消息
* 可重写修改
*/
override onMessage(message: any): void;
/**
* 向主线程发送消息
*/
postMessage(message: any, options: WorkerPostMessageOptions|null = null): void;
}
/**
* WorkerPostMessageOptions
*/
export type WorkerPostMessageOptions = {
/**
* 是否支持符合Sendable协议的对象作为共享变量发送,使用postMessageWithSharedSendable实现,默认值为false
* 仅鸿蒙平台支持,参考:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-sendable
*/
harmonySendable: boolean
/**
* 可转移对象数组,默认值为空数组
* 仅鸿蒙、web平台支持,参考:https://developer.mozilla.org/zh-CN/docs/Web/API/Web_Workers_API/Transferable_objects
*/
transfer: Array<any>
}
在主线程的代码中调用 uni.createWorker
创建并返回 Worker 对象,可通过其 onMessage
方法监听 Worker 子线程发送的数据,通过其 onError
方法监听 Worker 子线程的错误。
参考以下示例代码:
// 创建 Worker 实例
const worker = uni.createWorker('workers/HelloWorkerTask.uts');
// 监听 Worker 消息
worker.onMessage((message: any) => {
const messageData = message as UTSJSONObject;
console.log('收到Worker子线程数据:', messageData);
});
// 监听 Worker 错误
worker.onError((error: WorkerOnErrorCallbackResult) => {
console.error('Worker子线程发生错误:', error);
});
调用 uni.createWorker
创建并返回 Worker 对象的 postMessage
方法向 Worker 子线程发送数据。
参考以下示例代码:
// 向 Worker 子线程发送消息
worker.postMessage({
msg: 'message send by main!'
});
仅 HarmonyOS
和 Web
支持 示例:worker Sendable Transfer
仅 HarmonyOS 支持。示例:uts-worker-sendable-transfer
在 uts 插件的同级建立 ets 文件,导出 Sendable
对象 示例
@Sendable
export class SendableObject {
a: number = 45;
}
在 uts 插件中引入 注意引入时要有 .ets
后缀 示例
// #ifdef APP-HARMONY
import { SendableObject } from './sendable.ets';
// #endif
在 uts 插件中使用,向子线程发送 Sendable 对象 示例
workerImp.postMessage(new SendableObject())
在 worker 中接收到该对象后的修改会直接体现到宿主线程中
一个可转移对象数组。示例:worker Sendable Transfer
ArrayBuffer[]、MessagePort[]、ImageBitmap[]
等。 可转移对象ArrayBuffer[]
注意事项
Worker 线程不再使用需主动结束释放相关资源,调用 Worker 对象的 terminate
方法结束子线程。
参考以下示例代码:
// 结束 Worker 子线程
worker.terminate();
uni.createWorkder
仅支持在主线程中使用,在 Worker 子线程中使用会返回错误Worker.postMessage
发送这些共享对象时设置 harmonySendable
参数为 trueuvue
页面中调用 uni.createWorkder