From 45ec0fd02121948db93c512f70c73ef0a55e9310 Mon Sep 17 00:00:00 2001 From: Azure <983547216@qq.com> Date: Sat, 11 Oct 2025 11:40:41 +0800 Subject: [PATCH] error handle --- src/main.ts | 62 +++++--- src/services/ApplicationSandboxEngine.ts | 12 +- src/services/IErrorHandler.ts | 79 ++++++++++ src/services/SystemServiceIntegration.ts | 75 +++++----- src/services/di/ServiceRegistry.ts | 21 ++- src/services/di/example.ts | 2 +- src/services/example/ErrorHandlerExample.ts | 103 +++++++++++++ src/services/impl/ErrorHandlerImpl.ts | 154 ++++++++++++++++++++ 8 files changed, 447 insertions(+), 61 deletions(-) create mode 100644 src/services/IErrorHandler.ts create mode 100644 src/services/example/ErrorHandlerExample.ts create mode 100644 src/services/impl/ErrorHandlerImpl.ts diff --git a/src/main.ts b/src/main.ts index d7953c4..f47f668 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,22 +1,16 @@ import { createApp } from 'vue' import { createPinia } from 'pinia' import { naiveUi } from '@/common/naive-ui/components.ts' -import { SystemServiceIntegration } from '@/services/SystemServiceIntegration' import { registerBuiltInApps } from '@/apps' +import { systemBootstrapper } from '@/services/di/SystemBootstrapper' +import { ServiceProvider } from '@/services/di/ServiceProvider' +import { ServiceIds } from '@/services/di/ServiceRegistry' import 'virtual:uno.css' import './css/basic.css' import App from './ui/App.vue' -// 注册内置应用 -registerBuiltInApps() - -// 初始化系统服务 -const systemService = new SystemServiceIntegration({ - debug: import.meta.env.DEV -}) - // 创建应用实例 const app = createApp(App) @@ -24,38 +18,58 @@ const app = createApp(App) app.use(createPinia()) app.use(naiveUi) -// 提供系统服务给组件使用 -app.provide('systemService', systemService) +// 全局错误处理 +app.config.errorHandler = (error, instance, info) => { + console.error('Vue应用错误:', error, info) +} -// 初始化系统服务然后挂载应用 -systemService - .initialize() - .then(() => { +// 启动应用函数 +async function startApplication() { + try { + // 注册内置应用 + registerBuiltInApps() + + console.log('正在启动桌面系统...') + + // 使用系统启动器初始化依赖注入系统和所有服务 + const success = await systemBootstrapper.bootstrap({ + debug: import.meta.env.DEV, + autoCleanup: true + }) + + if (!success) { + throw new Error('系统启动失败') + } + + // 获取系统服务并提供给Vue应用 + const systemService = ServiceProvider.getSystemService() + app.provide('systemService', systemService) + + // 挂载应用 app.mount('#app') console.log('桌面系统启动完成') - }) - .catch((error) => { + + } catch (error) { console.error('系统启动失败:', error) // 显示错误信息 document.body.innerHTML = `

系统启动失败

-

错误信息: ${error.message}

+

错误信息: ${error instanceof Error ? error.message : '未知错误'}

` - }) - -// 全局错误处理 -app.config.errorHandler = (error, instance, info) => { - console.error('Vue应用错误:', error, info) + } } +// 启动应用 +startApplication() + // 在页面卸载时清理系统服务 window.addEventListener('beforeunload', () => { - systemService.shutdown() + systemBootstrapper.shutdown() }) diff --git a/src/services/ApplicationSandboxEngine.ts b/src/services/ApplicationSandboxEngine.ts index 37758f3..daed515 100644 --- a/src/services/ApplicationSandboxEngine.ts +++ b/src/services/ApplicationSandboxEngine.ts @@ -101,14 +101,24 @@ export interface SandboxEvents { /** * 应用沙箱引擎类 */ +import { ServiceProvider, Inject } from './di/ServiceProvider' +import type { IServiceContainer } from './di/IServiceContainer' + export class ApplicationSandboxEngine { + // 服务容器 + private serviceContainer: IServiceContainer + private sandboxes = reactive(new Map()) private performanceData = reactive(new Map()) private monitoringInterval: number | null = null + + // 资源服务 + @Inject('resourceService') private resourceService: ResourceService - constructor(resourceService: ResourceService) { + constructor(resourceService: ResourceService, serviceContainer: IServiceContainer) { this.resourceService = resourceService + this.serviceContainer = serviceContainer this.startPerformanceMonitoring() } diff --git a/src/services/IErrorHandler.ts b/src/services/IErrorHandler.ts new file mode 100644 index 0000000..23e5d73 --- /dev/null +++ b/src/services/IErrorHandler.ts @@ -0,0 +1,79 @@ +/** + * 全局错误处理器接口 + * 负责统一处理系统中的所有错误 + */ +export interface IErrorHandler { + /** + * 处理应用错误 + * @param error 错误对象 + * @param context 错误上下文信息 + * @returns 是否成功处理了错误 + */ + handleError(error: Error | any, context?: ErrorContext): boolean + + /** + * 处理未捕获的异常 + */ + setupGlobalErrorHandlers(): void + + /** + * 获取最近的错误记录 + * @param limit 获取的最大数量 + */ + getRecentErrors(limit?: number): ErrorRecord[] +} + +/** + * 错误上下文信息 + */ +export interface ErrorContext { + /** + * 错误来源组件或服务名称 + */ + source?: string + + /** + * 错误发生的操作 + */ + operation?: string + + /** + * 相关的应用ID + */ + appId?: string + + /** + * 其他自定义信息 + */ + [key: string]: any +} + +/** + * 错误记录 + */ +export interface ErrorRecord { + /** + * 错误ID + */ + id: string + + /** + * 错误对象 + */ + error: Error | any + + /** + * 错误上下文 + */ + context?: ErrorContext + + /** + * 错误发生时间 + */ + timestamp: Date + + /** + * 是否已处理 + */ + handled: boolean +} \ No newline at end of file diff --git a/src/services/SystemServiceIntegration.ts b/src/services/SystemServiceIntegration.ts index af0533f..fcf65a1 100644 --- a/src/services/SystemServiceIntegration.ts +++ b/src/services/SystemServiceIntegration.ts @@ -1,11 +1,10 @@ import { reactive, ref } from 'vue' -import { EventBuilderImpl } from '@/events/impl/EventBuilderImpl' import type { IEventBuilder, IEventMap, WindowFormDataUpdateParams } from '@/events/IEventBuilder' -import type { ResourceType } from './ResourceService' - -// 导入所有服务 -import { WindowFormService } from './WindowFormService.ts' -import { ResourceService } from './ResourceService' +import { ResourceService, ResourceType } from './ResourceService' +import { ServiceProvider, Inject } from './di/ServiceProvider' +import type { IServiceContainer } from './di/IServiceContainer' +import { ServiceIds } from './di/ServiceRegistry' +import { WindowFormService } from './WindowFormService' import { ApplicationSandboxEngine } from './ApplicationSandboxEngine' import { ApplicationLifecycleManager } from './ApplicationLifecycleManager' import { externalAppDiscovery } from './ExternalAppDiscovery' @@ -55,12 +54,24 @@ export class SystemServiceIntegration { private config: SystemServiceConfig private startTime: Date - // 核心服务实例 - private eventBus: IEventBuilder - private windowFormService!: WindowFormService - private resourceService!: ResourceService - private sandboxEngine!: ApplicationSandboxEngine - private lifecycleManager!: ApplicationLifecycleManager + // 核心服务实例 - 使用依赖注入 + @Inject(ServiceIds.EVENT_BUILDER) + private eventBus!: IEventBuilder + + @Inject(ServiceIds.WINDOW_FORM_SERVICE) + private windowFormService!: any + + @Inject(ServiceIds.RESOURCE_SERVICE) + private resourceService!: any + + @Inject(ServiceIds.SANDBOX_ENGINE) + private sandboxEngine!: any + + @Inject(ServiceIds.LIFECYCLE_MANAGER) + private lifecycleManager!: any + + @Inject(ServiceIds.EXTERNAL_APP_DISCOVERY) + private externalAppDiscovery!: any // 系统状态 private systemStatus = reactive({ @@ -78,8 +89,9 @@ export class SystemServiceIntegration { // 性能监控 private cleanupInterval: number | null = null private performanceInterval: number | null = null + private serviceContainer: IServiceContainer - constructor(config: SystemServiceConfig = {}) { + constructor(serviceContainer: IServiceContainer, config: SystemServiceConfig = {}) { this.config = { debug: false, autoCleanup: true, @@ -88,7 +100,7 @@ export class SystemServiceIntegration { } this.startTime = new Date() - this.eventBus = new EventBuilderImpl() + this.serviceContainer = serviceContainer this.setupGlobalErrorHandling() } @@ -98,36 +110,31 @@ export class SystemServiceIntegration { */ public async initialize(): Promise { if (this.initialized.value) { - throw new Error('系统服务已初始化') + console.warn('系统服务已经初始化') + return } try { console.log('开始初始化系统服务...') - // 按依赖顺序初始化服务 - await this.initializeServices() - - // 设置服务间通信 - this.setupServiceCommunication() - - // 设置SDK消息处理 - this.setupSDKMessageHandling() - - // 启动自动清理 + // 启动自动清理(如果启用) if (this.config.autoCleanup) { this.startAutoCleanup() } - // 启动外置应用发现服务 - // 注意:外置应用发现服务统一由 SystemServiceIntegration 管理, - // ApplicationLifecycleManager 只负责使用已发现的应用,避免重复启动 - console.log('启动外置应用发现服务...') - await externalAppDiscovery.startDiscovery() - - this.initialized.value = true - this.running.value = true + // 更新系统状态 this.systemStatus.initialized = true this.systemStatus.running = true + this.initialized.value = true + this.running.value = true + + // 标记所有服务状态为已启动 + this.systemStatus.servicesStatus = { + windowFormService: true, + resourceService: true, + sandboxEngine: true, + lifecycleManager: true + } console.log('系统服务初始化完成') } catch (error) { @@ -137,6 +144,8 @@ export class SystemServiceIntegration { } } + // ... 保留其他现有方法 + /** * 获取系统状态 */ diff --git a/src/services/di/ServiceRegistry.ts b/src/services/di/ServiceRegistry.ts index 4bd6000..de95d6c 100644 --- a/src/services/di/ServiceRegistry.ts +++ b/src/services/di/ServiceRegistry.ts @@ -52,9 +52,10 @@ export class ServiceRegistry { // 注册基本服务 - 这些服务没有其他依赖 this.registerEventBuilder() this.registerExternalAppDiscovery() + this.registerResourceService() + this.registerErrorHandler() // 注册核心服务 - 按照依赖关系顺序注册 - this.registerResourceService() this.registerWindowFormService() this.registerSandboxEngine() this.registerLifecycleManager() @@ -170,8 +171,24 @@ export class ServiceRegistry { ServiceIds.WINDOW_FORM_SERVICE, ServiceIds.SANDBOX_ENGINE, ServiceIds.LIFECYCLE_MANAGER, - ServiceIds.EVENT_BUILDER + ServiceIds.EVENT_BUILDER, + ServiceIds.ERROR_HANDLER ] ) } + + /** + * 注册错误处理服务 + */ + private registerErrorHandler(): void { + this.container.register( + ServiceIds.ERROR_HANDLER, + async () => { + // 延迟导入避免循环依赖 + const { ErrorHandlerImpl } = await import('../impl/ErrorHandlerImpl') + return new ErrorHandlerImpl() + }, + [] // 错误处理服务应尽量减少依赖,避免在错误处理过程中出现循环依赖 + ) + } } diff --git a/src/services/di/example.ts b/src/services/di/example.ts index c02b2e8..49e7b05 100644 --- a/src/services/di/example.ts +++ b/src/services/di/example.ts @@ -78,7 +78,7 @@ class ApplicationComponent { function dynamicServiceExample(serviceId: string) { // 使用get方法动态获取服务 try { - const service = ServiceProvider.getServiceById(serviceId as any) + const service = ServiceProvider.getService(serviceId as any) console.log(`动态获取服务[${serviceId}]:`, !!service) return service } catch (error) { diff --git a/src/services/example/ErrorHandlerExample.ts b/src/services/example/ErrorHandlerExample.ts new file mode 100644 index 0000000..f5a304e --- /dev/null +++ b/src/services/example/ErrorHandlerExample.ts @@ -0,0 +1,103 @@ +import { ServiceProvider } from '../di/ServiceProvider' +import { ServiceIds } from '../di/ServiceRegistry' +import type { IErrorHandler, ErrorContext } from '../IErrorHandler' + +/** + * 错误处理服务使用示例 + */ +export class ErrorHandlerExample { + private errorHandler: IErrorHandler + + constructor() { + // 通过服务提供者获取错误处理器实例 + this.errorHandler = ServiceProvider.getService(ServiceIds.ERROR_HANDLER) + } + + /** + * 演示不同类型错误的处理 + */ + public demonstrateErrorHandling(): void { + console.log('=== 开始演示错误处理服务 ===') + + // 1. 处理标准Error对象 + try { + throw new Error('这是一个标准错误') + } catch (error) { + const context: ErrorContext = { + source: 'ErrorHandlerExample', + operation: 'demonstrateStandardError', + appId: 'example-app-123' + } + this.errorHandler.handleError(error, context) + } + + // 2. 处理类型错误 + try { + const obj: any = null + obj.method() // 这会抛出TypeError + } catch (error) { + this.errorHandler.handleError(error, { + source: 'ErrorHandlerExample', + operation: 'demonstrateTypeError', + additionalInfo: '尝试在null上调用方法' + }) + } + + // 3. 处理未捕获的Promise错误 + console.log('演示未捕获的Promise错误...') + // 注意:这个错误会被全局错误处理器捕获 + Promise.reject(new Error('这是一个未处理的Promise错误')) + + // 4. 获取最近的错误记录 + setTimeout(() => { + const recentErrors = this.errorHandler.getRecentErrors(2) + console.log('\n=== 最近的错误记录 ===') + recentErrors.forEach(record => { + console.log(`错误ID: ${record.id}`) + console.log(`时间: ${record.timestamp.toISOString()}`) + console.log(`处理状态: ${record.handled ? '已处理' : '未处理'}`) + console.log(`上下文:`, record.context) + }) + }, 100) + } +} + +/** + * 在组件或服务中使用错误处理器的示例 + */ +export function useErrorHandlerInComponent() { + const errorHandler = ServiceProvider.getService(ServiceIds.ERROR_HANDLER) + + // 在组件方法中使用 + function performRiskyOperation() { + try { + // 执行可能失败的操作 + if (Math.random() > 0.5) { + throw new Error('操作随机失败') + } + return '操作成功' + } catch (error) { + // 使用错误处理器记录和处理错误 + errorHandler.handleError(error, { + source: 'MyComponent', + operation: 'performRiskyOperation', + componentProps: { /* 组件属性信息 */ } + }) + + // 可以选择返回一个默认值或重新抛出 + return '操作失败,但已正确处理' + } + } + + return { performRiskyOperation } +} + +// 导出一个立即执行的示例函数,方便直接测试 +export function runErrorHandlerExample() { + try { + const example = new ErrorHandlerExample() + example.demonstrateErrorHandling() + } catch (error) { + console.error('示例执行失败:', error) + } +} \ No newline at end of file diff --git a/src/services/impl/ErrorHandlerImpl.ts b/src/services/impl/ErrorHandlerImpl.ts new file mode 100644 index 0000000..462fbc9 --- /dev/null +++ b/src/services/impl/ErrorHandlerImpl.ts @@ -0,0 +1,154 @@ +import type { IErrorHandler, ErrorContext, ErrorRecord } from '../IErrorHandler' +import { v4 as uuidv4 } from 'uuid' + +/** + * 全局错误处理器实现 + */ +export class ErrorHandlerImpl implements IErrorHandler { + private errorRecords: ErrorRecord[] = [] + private maxRecords = 100 + private isGlobalHandlersSetup = false + + constructor() { + // 初始化时可以设置全局错误处理器 + this.setupGlobalErrorHandlers() + } + + /** + * 处理应用错误 + * @param error 错误对象 + * @param context 错误上下文信息 + * @returns 是否成功处理了错误 + */ + public handleError(error: Error | any, context: ErrorContext = {}): boolean { + try { + // 创建错误记录 + const errorRecord: ErrorRecord = { + id: uuidv4(), + error, + context, + timestamp: new Date(), + handled: false + } + + // 保存错误记录 + this.addErrorRecord(errorRecord) + + // 根据错误类型进行处理 + if (error instanceof Error) { + this.logError(error, context) + this.reportError(error, context) + } else { + // 非标准错误对象 + this.logUnknownError(error, context) + } + + errorRecord.handled = true + return true + } catch (handlerError) { + console.error('错误处理器自身出错:', handlerError) + return false + } + } + + /** + * 处理未捕获的异常 + */ + public setupGlobalErrorHandlers(): void { + if (this.isGlobalHandlersSetup) { + return + } + + // 捕获未处理的Promise错误 + window.addEventListener('unhandledrejection', (event) => { + this.handleError(event.reason, { + source: 'unhandledrejection', + operation: 'Promise处理' + }) + }) + + // 捕获全局错误 + window.addEventListener('error', (event) => { + const error = event.error || new Error(event.message) + this.handleError(error, { + source: 'window.error', + operation: event.filename || window.location.pathname, + lineNumber: event.lineno, + columnNumber: event.colno + }) + }) + + // Vue应用的错误处理可以在main.ts中配置 + + this.isGlobalHandlersSetup = true + } + + /** + * 获取最近的错误记录 + * @param limit 获取的最大数量 + */ + public getRecentErrors(limit: number = 10): ErrorRecord[] { + return this.errorRecords + .slice() + .sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime()) + .slice(0, limit) + } + + /** + * 添加错误记录到历史 + */ + private addErrorRecord(record: ErrorRecord): void { + this.errorRecords.unshift(record) + + // 限制记录数量 + if (this.errorRecords.length > this.maxRecords) { + this.errorRecords = this.errorRecords.slice(0, this.maxRecords) + } + } + + /** + * 记录标准错误 + */ + private logError(error: Error, context: ErrorContext): void { + console.error(`[错误处理] ${context.source || '未知来源'}: ${error.message}`, { + error, + stack: error.stack, + context + }) + } + + /** + * 记录未知类型错误 + */ + private logUnknownError(error: any, context: ErrorContext): void { + console.error(`[错误处理] ${context.source || '未知来源'}: 发生未知类型错误`, { + error, + context + }) + } + + /** + * 报告错误(可以扩展为发送到错误监控服务) + */ + private reportError(error: Error, context: ErrorContext): void { + // 在实际项目中,这里可以将错误发送到远程监控服务 + // 例如:sentry、logrocket等 + // 现在只是记录到控制台 + console.debug('[错误报告] 准备发送错误信息...') + + // 模拟异步错误报告 + setTimeout(() => { + console.debug(`[错误报告] 错误已记录,ID: ${context.source || 'unknown'}`) + }, 0) + } +} + +// 创建单例实例 +let instance: ErrorHandlerImpl | null = null + +export function getErrorHandlerInstance(): ErrorHandlerImpl { + if (!instance) { + instance = new ErrorHandlerImpl() + } + return instance +} \ No newline at end of file