alloy worker 代码约定
Alloy-worker 对 postMessage
/onmessage
通信 API 进行了 RPC 封装. 通过代码约定, 使代码编写更加简洁, 功能维护和拓展更加容易.
跨线程的业务功能. 事务用于实现线程间的一项特定业务功能, 类似 HTTP 通信的一个后台接口.
比如:
-
communicationTest
事务用于检查跨线程通信能力. -
heartBeatTest
事务用于检测 Worker 线程心跳.
每项事务有唯一的 id, 类似 HTTP 的后台接口有各自的 url. 事务 id 约定为事务名称字符串.
同类型事务的集合. 一个命名空间的源码为一个文件; 运行时事务通过命名空间调用. 命名空间类似 HTTP 中不同的后台域名.
比如:
- 命名空间
workerAbilityTest
包括communicationTest
和heartBeatTest
2 个事务. - 命名空间
workerAbilityTest
源码在worker-ability-test.ts
. - 运行时通过
workerAbilityTest.communicationTest
和workerAbilityTest.heartBeatTest
调用.
通信负载是跨线程通信中传递的数据, 包括发送负载和响应负载. 类似 HTTP 中的 Request 和 Response.
Alloy-worker 使用 TypeScript 添加通信负载类型声明, 避免传输错误的负载, 导致另一线程处理出错.
通信控制器负责不同事务的处理, 包括发送事务和注册事务处理器.
比如:
- 通过
controller.requestPromise
发送事务, 得到一个等待回复的 Promise. - 如果不需要回复, 可通过
controller.request
发送事务. - 通过
controller.addActionHandler
添加事务处理器.
通信通道维护每次独立的通信会话(session). 对接 Worker 原生 API, 每次通信生成会话 ud, 通信请求能接收到配对的响应.
通信通道是 alloy-worker 的内部模块, 业务开发中不需要调用.
src/worker
├── common
│ ├── action-type.ts // 事务类型声明
│ └── payload-type.ts // 负载类型声明
├── config.ts // 运行配置
├── index.ts // 入口
├── one-script // 事务生成脚本
├── report-proxy.ts // 上报代理
├── main-thread // 主线程事务
│ ├── cookie.ts
│ ├── index.ts
│ └── worker-ability-test.ts
└── worker-thread // worker 线程事务
├── cookie.ts
├── index.ts // worker 独立打包入口
└── worker-ability-test.ts
主线程事务源码和 Worker 线程事务源码分别在 ./main-thread
和 ./worker-thread
目录下.
跨线程事务通过文件名实现命名空间, 并且约定线程间的文件名称保持一致. 查找时可以通过同名文件找到另一线程源码.
'./main-thread/worker-ability-test.ts' <---> './worker-thread/worker-ability-test.ts'
'./main-thread/cookie.ts' <---> './worker-thread/cookie.ts'
事务约定为在同名文件中的相名函数. 在一个线程为事务发送函数, 在另一线程则为事务处理函数.
// src/worker/main-thread/worker-ability-test.ts
export default class WorkerAbilityTest extends BaseAction {
// 发送通信能力检查事务
public communicationTest() {}
// 发送心跳检测事务
public heartBeatTest() {}
}
// src/worker/worker-thread/worker-ability-test.ts
export default class WorkerAbilityTest extends BaseAction {
// 处理通信能力检查事务
private communicationTest() {
return xxx;
}
// 处理心跳检测事务
private heartBeatTest() {
return xxx;
}
}
事务命名空间和事务 id 的声明文件为 action-type.ts
:
// src/worker/common/action-type.ts
export const enum WorkerAbilityTestActionType {
CommunicationTest = 'CommunicationTest',
HeartBeatTest = 'HeartBeatTest',
}
事务的发送负载和响应负载的声明文件为 payload-type.ts
:
// src/worker/common/payload-type.ts
// 发送负载(WorkerPayload)
declare namespace WorkerPayload {
namespace WorkerAbilityTest {
type CommunicationTest = number;
type HeartBeatTest = xxx;
}
}
// 响应负载(WorkerResponse)
declare namespace WorkerReponse {
namespace WorkerAbilityTest {
type CommunicationTest = number;
type HeartBeatTest = xxx;
}
}
- 主线程实例化 alloy-worker.
// src/index.ts
import createAlloyWorker from '../worker/index';
// 实例化
const alloyWorker = createAlloyWorker({
workerName: 'alloyWorker--test',
});
// 跨线程 Promise 调用
alloyWorker.workerAbilityTest.communicationTest().then(console.log);
- 主线程发起跨线程调用.
// src/worker/main-thread/worker-ability-test.ts
export default class WorkerAbilityTest {
communicationTest() {
const mainThreadPostTime: = Date.now();
// this.controller 为通信控制器
return this.controller.requestPromise(
WorkerAbilityTestActionType.CommunicationTest,
mainThreadPostTime);
}
}
- Worker 线程收到请求并返回结果.
// src/worker/worker-thread/worker-ability-test.ts
export default class WorkerAbilityTest {
CommunicationTest(payload) {
// 获取主线程传递的数据
const mainThreadPostTime = payload;
// 返回发送和接收的时间差
return Date.now() - mainThreadPostTime;
}
}
以 communicationTest
事务为例介绍事务的跨线程调用流程.
// src/worker/main-thread/worker-ability-test.ts
communicationTest(): Promise<WorkerReponse.WorkerAbilityTest.CommunicationTest> {
const mainThreadPostTime: WorkerPayload.WorkerAbilityTest.CommunicationTest = Date.now();
return this.controller.requestPromise(
WorkerAbilityTestActionType.CommunicationTest,
mainThreadPostTime);
}
其中:
-
WorkerPayload.WorkerAbilityTest.CommunicationTest
为发送负载的类型声明. -
WorkerReponse.WorkerAbilityTest.CommunicationTest
为响应负载的类型声明. - alloy-worker 将通信封装为 Promise, 所以
communicationTest
返回Promise<T>
. -
this.controller
为主线程通信控制器, 调用requestPromise
发送事务, 参数为事务类型和负载. -
WorkerAbilityTestActionType.CommunicationTest
为事务类型的字符串, 用以区分不同的事务.
跨线程事务发送到 Worker 线程时, Worker 线程调用相应的处理函数. 需要添加事务监听:
// src/worker/worker-thread/worker-ability-test.ts
protected addActionHandler(): void {
this.controller.addActionHandler(
WorkerAbilityTestActionType.CommunicationTest,
this.CommunicationTest.bind(this)
);
...
}
其中:
- 在
addActionHandler
函数用于添加各事务的事件监听. -
this.controller
为 Wokrer 线程的通信控制器. - 调用
this.controller.addActionHandler
添加事务监听, 参数为事务类型和事务处理函数.
事务处理函数对具体事务进行处理, 处理结果作为跨线程事务的响应返回给主线程.
// src/worker/worker-thread/worker-ability-test.ts
private CommunicationTest(
payload: WorkerPayload.WorkerAbilityTest.CommunicationTest
): WorkerReponse.WorkerAbilityTest.CommunicationTest {
const mainThreadPostTime = payload;
// 收到主线程信息的耗时
const workerGetMessageDuration = Date.now() - mainThreadPostTime;
return workerGetMessageDuration;
}
其中:
-
CommunicationTest
与主线程发起事务的函数同名. - 返回结果类型为
WorkerReponse.WorkerAbilityTest.CommunicationTest
. -
CommunicationTest
函数中可以随意调用外部模块的函数.
在业务侧, 事务处理函数可能需要等待异步逻辑, 如等待后台请求数据, indexDB 查找结果等. Alloy-worker 支持事务处理函数为异步函数, 只需要使用 async/await 进行函数声明.
将同步的 CommunicationTest
修改为异步:
// src/worker/worker-thread/worker-ability-test.ts
- private CommunicationTest(
+ private async CommunicationTest(
payload: WorkerPayload.WorkerAbilityTest.CommunicationTest
-): WorkerReponse.WorkerAbilityTest.CommunicationTest {
+): Promise<WorkerReponse.WorkerAbilityTest.CommunicationTest> {
WorkerThreadWorker.cookie.getCookie();
const mainThreadPostTime = payload;
// 收到主线程信息的耗时
const workerGetMessageDuration = Date.now() - mainThreadPostTime;
+ await new Promise(...);
return workerGetMessageDuration;
}
其中:
- 事务处理函数添加
async
关键字声明. - 事务处理函数的返回类型修改为
Promise<T>
. - 在事务处理函数中通过
await
等待异步 Promise 逻辑.