Browse Source

feat: 框架三大件写完

es6
iapyang 2 years ago
parent
commit
4465d0a441
  1. 200
      typescript/core/worker/worker.channel.ts
  2. 131
      typescript/core/worker/worker.controller.ts
  3. 32
      typescript/core/worker/worker.ts

200
typescript/core/worker/worker.channel.ts

@ -0,0 +1,200 @@
import { IWorkerController, WorkerMessageType, IWorkerMessage } from './worker';
const COMMUNICATION_TIMEOUT = 30000;
/**
*
*/
export class WorkerChannel {
/**
* Web Worker
*/
private worker: Worker;
/**
*
*/
private controller: IWorkerController;
/**
* Map
*/
private sessionHandlerMap: {
[propsName: string]: Function;
};
public constructor(worker: Worker, controller: IWorkerController) {
this.worker = worker;
this.controller = controller;
this.sessionHandlerMap = {};
// 绑定 worker onmessage 事件的回调
this.worker.addEventListener('message', this.onmessage.bind(this));
}
/**
*
*
* @param sessionId Id
* @param payload
*/
public response(sessionId: string, actionType: string, payload: any): void {
this.postMessage({
messageType: WorkerMessageType.REPLY,
actionType,
payload,
sessionId,
});
}
/**
* ,
*
* @param actionType
* @param payload
*/
public request(actionType: string, payload: any): void {
const sessionId = this.generateSessionId();
this.postMessage({
messageType: WorkerMessageType.REQUEST,
actionType,
payload,
sessionId,
});
// 不等待结果, 还会收到响应, 添加个空的会话响应器
this.addSessionHandler(sessionId, () => {});
}
/**
* ,
*
* @param actionType
* @param payload
* @param timeout
* @returns {Promise<IWorkerMessage>} Promise
*/
public requestPromise<T>(actionType: string, payload: any, timeout = COMMUNICATION_TIMEOUT): Promise<T> {
const sessionId = this.generateSessionId();
const message = {
messageType: WorkerMessageType.REQUEST,
actionType,
payload,
sessionId,
};
// 请求封装为一个 Promise, 等待会话响应器进行 resolve
const PromiseFunction = (resolve: Function, reject: Function): any => {
// 启动请求超时计时器
const timeoutHandler = setTimeout(() => {
clearTimeout(timeoutHandler);
reject();
}, timeout);
const sessionHandler: Function = (message: IWorkerMessage) => {
// 会话回调函数, 开始处理响应
this.deleteSessionHandler(message.sessionId);
clearTimeout(timeoutHandler);
resolve(message.payload);
};
this.addSessionHandler(sessionId, sessionHandler);
// 开始发送请求
this.postMessage(message);
};
return new Promise(PromiseFunction);
}
/**
*
*
* , , ;
*
* @param event worker
*/
private onmessage(event: { data: IWorkerMessage }): void {
const { data: message } = event;
const { messageType, sessionId, actionType } = message;
// 接收到请求
if (messageType === WorkerMessageType.REQUEST) {
// 处理请求
this.controller.actionHandler(message)
.then(actionResult => {
// 响应请求
this.response(sessionId, actionType, actionResult);
});
}
// 接收到响应
if (messageType === WorkerMessageType.REPLY) {
// 处理响应
if (this.hasSessionHandler(sessionId)) {
this.sessionHandlerMap[sessionId](message);
} else {
throw new Error(`Session \`${sessionId}\` handler no exist`);
}
}
}
/**
* worker postMessage
* structured clone transfer 2
*
* @param message
*/
private postMessage(message: IWorkerMessage): void {
this.worker.postMessage(message);
}
/**
*
*
* @param sessionId Id
* @param handler
*/
private addSessionHandler(sessionId: string, handler: Function): void {
if (!this.hasSessionHandler(sessionId)) {
this.sessionHandlerMap[sessionId] = handler;
} else {
throw new Error(`SessionId \`${sessionId}\` already exist!`);
}
}
/**
*
*
* @param sessionId
*/
private deleteSessionHandler(sessionId: string): void {
if (this.hasSessionHandler(sessionId)) {
delete this.sessionHandlerMap[sessionId];
}
}
/**
* Id
*
* @returns Id
*/
private generateSessionId(): string {
const sessionId = `w_${BI.UUID()}`;
return sessionId;
}
/**
*
*
* @param sessionId Id
* @returns {boolean}
*/
private hasSessionHandler(sessionId: string): boolean {
return !!this.sessionHandlerMap[sessionId];
}
}

131
typescript/core/worker/worker.controller.ts

@ -0,0 +1,131 @@
import type { IWorkerController, IWorkerMessage } from './worker';
import { WorkerChannel } from './worker.channel';
/**
*
*
* @class BaseWorkerController
*/
export default class BaseWorkerController implements IWorkerController {
/**
* worker,
*/
protected worker: Worker;
/**
* Channel,
*/
protected channel: WorkerChannel;
/**
* Map
*/
protected actionHandlerMap: {
[propsName: string]: (payload: any) => any;
};
public constructor() {
this.actionHandlerMap = {};
}
/**
*
*
* @param actionType
* @param payload
*/
public request(actionType: string, payload: any): void {
if (this.channel) {
return this.channel.request(actionType, payload);
}
console.error('No channel.');
return;
}
/**
* Promise , then
*
* @param actionType
* @param payload
* @param [timeout] ; Worker , ,
*/
public requestPromise<T = any>(actionType: string, payload: any = '', timeout?: number): Promise<T> {
// 有 Channel 实例才能进行通信, 此时还没有实例化是浏览器不支持创建 worker
if (this.channel) {
return this.channel.requestPromise<T>(actionType, payload, timeout);
}
// 兼容上层调用的 .then().catch()
return Promise.reject(new Error('No channel.'));
}
/**
* ,
*
* @param actionType
* @param handler
*/
public addActionHandler(actionType: string, handler: (payload: any) => any): void {
if (this.hasActionHandler(actionType)) {
throw new Error(`Add action \`${actionType}\` handler repeat`);
}
this.actionHandlerMap[actionType] = handler;
}
/**
* , Channel
*
* @param message
* @returns
*/
public actionHandler(message: IWorkerMessage): Promise<any> {
const { actionType, payload } = message;
if (this.hasActionHandler(actionType)) {
// 执行指定的事务处理器, 并返回 Promise 封装的事务结果
try {
const actionResult = this.actionHandlerMap[actionType](payload);
// 对于 Promise 形式的结果, 需要进行 Promise 错误捕获
if (BI.isPromise(actionResult)) {
return actionResult.catch(error => Promise.reject(error));
}
// 对数据结果, 包装为 Promise
return Promise.resolve(actionResult);
} catch (error) {
// 继续抛出给外层
return Promise.reject(error);
}
} else {
throw new Error(`Not Found Session Handler \`${actionType}\`.`);
}
}
/**
* worker onmessage
*
* @param {(event: any) => void} onmessage
* @returns {() => void}
*/
public addOnmessageListener(onmessage: (event: any) => void): () => void {
this.worker.addEventListener('message', onmessage);
// 返回移除监听函数
return () => {
this.worker.removeEventListener('message', onmessage);
};
}
/**
*
*
* @param actionType
* @returns {boolean}
*/
protected hasActionHandler(actionType: string): boolean {
return !!this.actionHandlerMap[actionType];
}
}

32
typescript/core/worker/worker.ts

@ -0,0 +1,32 @@
/**
*
*/
export const enum WorkerMessageType {
REQUEST = 'REQUEST',
REPLY = 'REPLY',
}
/**
*
*/
export interface IWorkerMessage {
messageType: WorkerMessageType;
actionType: string;
sessionId: string;
/**
*
*/
payload: any;
}
/**
* interface
*/
export interface IWorkerController {
/**
*
*/
actionHandler: (message: IWorkerMessage) => Promise<any>;
}
Loading…
Cancel
Save