UNPKG

dehub

Version:
421 lines (420 loc) 13.3 kB
"use strict"; /** * 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);