Skip to content

alloy worker 代码约定

CntChen edited this page Jul 11, 2020 · 2 revisions

Alloy-worker 对 postMessage/onmessage 通信 API 进行了 RPC 封装. 通过代码约定, 使代码编写更加简洁, 功能维护和拓展更加容易.

相关概念

事务(action)

跨线程的业务功能. 事务用于实现线程间的一项特定业务功能, 类似 HTTP 通信的一个后台接口.

比如:

  • communicationTest 事务用于检查跨线程通信能力.
  • heartBeatTest 事务用于检测 Worker 线程心跳.

每项事务有唯一的 id, 类似 HTTP 的后台接口有各自的 url. 事务 id 约定为事务名称字符串.

事务命名空间(namespace)

同类型事务的集合. 一个命名空间的源码为一个文件; 运行时事务通过命名空间调用. 命名空间类似 HTTP 中不同的后台域名.

比如:

  • 命名空间 workerAbilityTest 包括 communicationTestheartBeatTest 2 个事务.
  • 命名空间 workerAbilityTest 源码在 worker-ability-test.ts.
  • 运行时通过 workerAbilityTest.communicationTestworkerAbilityTest.heartBeatTest 调用.

通信负载(payload)

通信负载是跨线程通信中传递的数据, 包括发送负载和响应负载. 类似 HTTP 中的 Request 和 Response.

Alloy-worker 使用 TypeScript 添加通信负载类型声明, 避免传输错误的负载, 导致另一线程处理出错.

通信控制器(controller)

通信控制器负责不同事务的处理, 包括发送事务和注册事务处理器.

比如:

  • 通过 controller.requestPromise 发送事务, 得到一个等待回复的 Promise.
  • 如果不需要回复, 可通过 controller.request 发送事务.
  • 通过 controller.addActionHandler 添加事务处理器.

通信通道(channel)

通信通道维护每次独立的通信会话(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 事务为例介绍事务的跨线程调用流程.

主线程调用 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 线程时, 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 添加事务监听, 参数为事务类型和事务处理函数.

Worker 线程的事务处理函数

事务处理函数对具体事务进行处理, 处理结果作为跨线程事务的响应返回给主线程.

// 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 逻辑.

EOF