fineui是帆软报表和BI产品线所使用的前端框架。
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

201 lines
5.5 KiB

import { IWorkerController, WorkerMessageType, IWorkerMessage } from './worker.core';
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];
}
}