dehub
Version:
Data&Event MessageHub.
421 lines (420 loc) • 13.3 kB
JavaScript
;
/**
* DEHub 模块
* 这是一个事件中心模块,负责管理组件注册、事件分发和组件间通信
* @module DEHub
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.stop = exports.when = exports.error = exports.emit = exports.delComponent = exports.regComponent = exports.getComponent = exports.clearComponentSession = exports.EventContext = exports.DEHubConfig = void 0;
const lodash_1 = require("lodash");
const DETypes_1 = require("./DETypes");
// 全局组件映射表
const compMap = new Map();
// 全局事件处理函数映射表
const funcMap = new Map();
// 标签及其子标签缓存映射表
const tagSelfChildMap = new Map();
let regCmpTimeId;
let cmpInited = false;
// 默认配置选项
let _options = {
FuncExeTimeout: 3000,
AppLoadEventDelay: 517
};
/**
* 配置DEHub选项
* @param options - 配置选项
*/
const DEHubConfig = (options) => {
_options = { ..._options, ...options };
};
exports.DEHubConfig = DEHubConfig;
/**
* Event Context
* 事件上下文
*/
class EventContext {
#emitContext;
#cancel;
#output;
constructor(emitContext, output) {
this.#emitContext = emitContext;
this.#cancel = false;
this.#output = output;
}
get sender() {
return this.#emitContext.sender;
}
get event() {
return this.#emitContext.event;
}
get stage() {
return this.#emitContext.stage;
}
get detail() {
return this.#emitContext.detail;
}
get status() {
return this.#emitContext.status;
}
get attribute() {
return this.#emitContext.attribute;
}
get property() {
return this.#emitContext.property;
}
get database() {
return this.#emitContext.database;
}
/**
* Cancel the event
* 取消事件
*/
get cancel() {
return this.#cancel;
}
set cancel(value) {
this.#cancel = value;
}
/**
* Output of the event
* 事件的输出
*/
get output() {
return this.#output;
}
/**
* Components of the event
* 事件的组件列表
*/
get components() {
return compMap;
}
}
exports.EventContext = EventContext;
/**
* 清除组件会话存储
*/
const clearComponentSession = () => {
sessionStorage.clear();
};
exports.clearComponentSession = clearComponentSession;
/**
* 根据标签获取组件
* @param tag - 组件标签,可以是Tag对象、ObjTag对象或字符串
* @returns 返回匹配的组件或undefined
*/
const getComponent = (tag) => {
if (typeof tag === 'string') {
return compMap.get(tag);
}
let targetCmp;
if (tag instanceof DETypes_1.Tag) {
targetCmp = compMap.get(tag.path);
}
else {
targetCmp = compMap.get(new DETypes_1.Tag(tag).path);
}
return targetCmp;
};
exports.getComponent = getComponent;
/**
* 处理组件注册后的操作
* @param comp - 要注册的组件
* @param preContext - 预处理上下文
*/
const postRegComponent = (comp, preContext) => {
const postContext = { ...preContext, stage: DETypes_1.EventStage.PostOperation };
comp.waitReady().then(() => {
const [postResponse, allPostFuncsResult] = (0, exports.emit)(postContext);
if (postResponse.cancel) {
return;
}
Promise.allSettled(allPostFuncsResult).then((results) => {
(0, DETypes_1.rejectedCheck)(results);
}).catch(e => {
(0, exports.error)(comp, e);
});
}).catch((reason) => {
(0, exports.error)(comp, reason);
throw reason;
});
};
/**
* 注册组件
* @param comp - 要注册的组件
* @returns 返回注册的组件
*/
const regComponent = (comp) => {
let preContext = {
sender: comp,
event: DETypes_1.EventNames.Registration,
stage: DETypes_1.EventStage.PreOperation,
detail: comp
};
const [preResponse, allPreFuncsResult] = (0, exports.emit)(preContext);
if (preResponse.cancel) {
return comp;
}
compMap.set(comp.tag.path, comp);
if (!allPreFuncsResult || allPreFuncsResult.length === 0) {
postRegComponent(comp, preContext);
}
else {
Promise.allSettled(allPreFuncsResult).then((results) => {
(0, DETypes_1.rejectedCheck)(results);
postRegComponent(comp, preContext);
}).catch((reason) => {
(0, exports.error)(comp, reason);
throw reason;
});
}
return comp;
};
exports.regComponent = regComponent;
/**
* 删除组件
* @param comp - 要删除的组件
* @returns Promise<void>
*/
const delComponent = (comp) => {
return new Promise(async (resolve, reject) => {
const path = comp.tag.path;
const target = compMap.get(path);
if (!target) {
return resolve();
}
const preContext = {
sender: target,
event: DETypes_1.EventNames.WillUnmount,
stage: DETypes_1.EventStage.PreOperation,
detail: target
};
try {
const [preResponse, prePromises] = (0, exports.emit)(preContext);
if (preResponse.cancel) {
return resolve();
}
await Promise.allSettled(prePromises).then(results => {
(0, DETypes_1.rejectedCheck)(results);
});
compMap.delete(path);
const postContext = { ...preContext, stage: DETypes_1.EventStage.PostOperation };
const [postResponse, postPromises] = (0, exports.emit)(postContext);
if (postResponse.cancel) {
return resolve();
}
await Promise.allSettled(postPromises).then(results => {
(0, DETypes_1.rejectedCheck)(results);
});
resolve();
}
catch (err) {
await (0, exports.error)(comp, err);
reject(err);
}
});
};
exports.delComponent = delComponent;
/**
* 构建事件标签
* @param context - 事件上下文
* @param proxyTag - 代理标签
* @returns 返回构建的Tag对象
*/
const buildEventTags = (context, proxyTag = {}) => {
let eventTags = {
...(context.sender instanceof DETypes_1.Tag ? context.sender.members : context.sender?.tag?.members || {}),
event: context.event,
stage: context.stage
};
if (context.attribute)
eventTags.attribute = context.attribute;
if (context.property)
eventTags.property = context.property;
if (context.status)
eventTags.status = context.status;
if (context.database)
eventTags.database = context.database;
if (Object.keys(proxyTag).length > 0) {
(0, lodash_1.assign)(eventTags, proxyTag);
}
return new DETypes_1.Tag(eventTags);
};
/**
* 触发事件
* @param context - 事件上下文
* @param proxyTag - 代理标签
* @returns [事件上下文, Promise数组, 事件ID]
*/
const emit = (context, proxyTag = {}) => {
const emitId = (0, lodash_1.uniqueId)('e');
const eventTags = buildEventTags(context, proxyTag);
let allEventPaths = tagSelfChildMap.get(eventTags.path);
if (!allEventPaths) {
allEventPaths = DETypes_1.TagsSerializer.selfAndChildTags(eventTags);
tagSelfChildMap.set(eventTags.path, allEventPaths);
}
const output = {};
const eventContext = new EventContext(context, output);
const asyncFuncList = [];
const promiseResults = {
'Pending': [],
'Fulfilled': [],
'Rejected': []
};
foreachEvents: for (const ePath of allEventPaths) {
const handlers = funcMap.get(ePath) ?? [];
if (handlers.length === 0) {
continue;
}
for (const handler of handlers) {
try {
const result = handler.function(eventContext);
if (result instanceof Promise) {
asyncFuncList.push(result);
result.then(() => {
promiseResults.Fulfilled.push(handler);
}).catch(() => {
promiseResults.Rejected.push(handler);
});
setTimeout(() => {
if (!promiseResults.Rejected.includes(handler) &&
!promiseResults.Fulfilled.includes(handler)) {
promiseResults.Pending.push(handler);
console.warn(`[${emitId}]异步事件(${ePath})\r\n函数${handler.alias ?? handler.name}执行超时。\n 函数:`, handler, "\nContext:", eventContext);
}
}, _options.FuncExeTimeout);
}
if (eventContext.cancel === true) {
break foreachEvents;
}
}
catch (err) {
if (eventTags.members.event !== DETypes_1.EventNames.Exception) {
(0, exports.error)(context.sender, err);
}
throw err;
}
}
}
return [eventContext, asyncFuncList, emitId];
};
exports.emit = emit;
/**
* 错误处理
* @param sender - 错误发送者
* @param exception - 错误对象
* @returns Promise<[EventContext | null, Promise<any>[]]>
*/
const error = async (sender, exception) => {
const errorTags = {
sender,
event: DETypes_1.EventNames.Exception,
stage: DETypes_1.EventStage.PostOperation,
detail: typeof exception === 'string' ? new Error(exception) : exception
};
try {
const [output, errPromises] = (0, exports.emit)(errorTags);
return [output, errPromises];
}
catch (err) {
console.error('Error in error handler:', err);
return [null, []];
}
};
exports.error = error;
/**
* 注册事件监听
* @param tagFilter - 标签过滤器
* @param callback - 回调函数
* @param alias - 函数别名
*/
const when = (tagFilter, callback, alias) => {
if (!tagFilter.event && tagFilter.status === DETypes_1.ObjectStatus.Loading) {
tagFilter.event = DETypes_1.EventNames.Submit;
}
const filterTag = new DETypes_1.Tag(tagFilter);
let tags = tagSelfChildMap.get(filterTag.path);
if (!tags) {
tags = DETypes_1.TagsSerializer.selfAndChildTags(filterTag);
tagSelfChildMap.set(filterTag.path, tags);
}
let targetFuns = funcMap.get(filterTag.path) ?? [];
const funcItem = {
function: callback,
name: callback.name || 'anonymous',
alias: alias ?? (callback.name || 'anonymous')
};
if (targetFuns.find(t => (0, lodash_1.isEqual)(t.function, funcItem.function))) {
return;
}
targetFuns.push(funcItem);
funcMap.set(filterTag.path, targetFuns);
};
exports.when = when;
/**
* 移除事件监听
* @param tagFilter - 标签过滤器
* @param callback - 要移除的回调函数
*/
const stop = (tagFilter, callback) => {
if (!tagFilter.event && tagFilter.status === DETypes_1.ObjectStatus.Loading) {
tagFilter.event = DETypes_1.EventNames.Submit;
}
const tag = new DETypes_1.Tag(tagFilter);
let targetFuns = funcMap.get(tag.path) ?? [];
const targetIndex = targetFuns.findIndex(t => (0, lodash_1.isEqual)(t.function, callback));
targetIndex >= 0 && targetFuns.splice(targetIndex, 1);
if (targetFuns.length === 0) {
funcMap.delete(tag.path);
tagSelfChildMap.delete(tag.path);
}
else {
funcMap.set(tag.path, targetFuns);
}
};
exports.stop = stop;
/**
* 应用组件加载完成处理函数
* @param context - 事件上下文
*/
const appCmpLoadedHandler = (context) => {
const comp = context.sender;
/** 组件加载完成判断,延迟500毫秒 */
if (cmpInited === false) {
regCmpTimeId && clearTimeout(regCmpTimeId);
regCmpTimeId = setTimeout(async () => {
cmpInited = true;
let appLoadedContext = {
sender: comp,
event: DETypes_1.EventNames.ComponentsLoaded,
stage: DETypes_1.EventStage.PostOperation,
detail: comp
};
try {
const [appResponse, allPostFuncsResult] = (0, exports.emit)(appLoadedContext);
if (appResponse.cancel) {
cmpInited = false;
return comp;
}
allPostFuncsResult && (0, DETypes_1.rejectedCheck)(await Promise.allSettled(allPostFuncsResult));
//注销事件侦听
(0, exports.stop)({
event: DETypes_1.EventNames.Registration,
stage: DETypes_1.EventStage.PreOperation
}, appCmpLoadedHandler);
}
catch (err) {
cmpInited = false;
await (0, exports.error)(comp, err);
return comp;
}
}, _options.AppLoadEventDelay);
}
};
// 注册应用组件加载完成事件监听
(0, exports.when)({
event: DETypes_1.EventNames.Registration,
stage: DETypes_1.EventStage.PreOperation
}, appCmpLoadedHandler);