dromara/electron-egg 应用退出策略与资源清理

dromara/electron-egg 应用退出策略与资源清理

【免费下载链接】electron-egg A simple, cross platform, enterprise desktop software development framework 【免费下载链接】electron-egg 项目地址: https://gitcode.com/dromara/electron-egg

在桌面应用开发中,应用的退出流程往往被忽视,却直接影响用户体验和系统稳定性。当用户点击关闭按钮时,未保存的文档、正在进行的网络请求、临时文件残留等问题可能导致数据丢失或系统资源泄漏。electron-egg 作为企业级桌面软件开发框架,提供了完善的生命周期管理机制,本文将深入探讨如何在该框架下实现优雅的应用退出策略与资源清理方案。

应用退出流程概述

electron-egg 基于 Electron 构建,其退出流程涉及主进程(Main Process)与渲染进程(Renderer Process)的协同工作。框架通过生命周期钩子(Lifecycle Hooks)机制,允许开发者在应用退出的不同阶段插入自定义逻辑,实现资源释放、状态保存等关键操作。

退出流程核心组件

组件路径作用
electron/main.js应用入口,注册生命周期钩子
electron/preload/lifecycle.js生命周期管理类,包含退出前清理方法
electron/config/config.default.js窗口配置,影响退出行为

标准退出流程

mermaid

生命周期钩子与退出前清理

electron-egg 的生命周期管理是实现优雅退出的核心。框架提供了 before-close 钩子,专门用于处理应用退出前的资源清理工作。

Lifecycle 类实现

electron/preload/lifecycle.js 中定义的 Lifecycle 类包含了关键的退出前处理方法:

public class Lifecycle {
  /**
   * before app close
   */  
  async beforeClose() {
    logger.info('[lifecycle] before-close');
    // 在这里添加资源清理逻辑
  }
}

该方法在应用关闭前被自动调用,是执行资源清理的最佳位置。默认实现仅记录日志,开发者需根据应用需求扩展其功能。

钩子注册流程

在应用入口文件 electron/main.js 中,Lifecycle 实例的 before-close 方法被注册到框架中:

// 注册 lifecycle
const life = new Lifecycle();
app.register("before-close", life.beforeClose);

这种设计使得退出前清理逻辑与主流程解耦,符合开闭原则,便于维护和扩展。

常见资源清理场景与实现

不同类型的应用需要清理的资源各不相同,以下是企业级应用中常见的清理场景及基于 electron-egg 的实现方案。

1. 数据持久化

在退出前保存用户会话状态或未保存的文档:

async beforeClose() {
  logger.info('[lifecycle] before-close: saving user session');
  
  try {
    // 获取渲染进程中的未保存数据
    const unsavedData = await ipcRenderer.invoke('get-unsaved-data');
    
    if (unsavedData && unsavedData.length > 0) {
      // 保存到本地文件
      await fs.promises.writeFile(
        path.join(app.getPath('userData'), 'session.json'),
        JSON.stringify(unsavedData)
      );
      logger.info(`[lifecycle] Saved ${unsavedData.length} items to session storage`);
    }
  } catch (error) {
    logger.error('[lifecycle] Failed to save user session', error);
    // 可选择显示错误对话框
  }
}

2. 网络连接清理

关闭WebSocket连接或取消挂起的HTTP请求:

async beforeClose() {
  logger.info('[lifecycle] before-close: cleaning network connections');
  
  // 关闭WebSocket连接
  if (global.socketClient && global.socketClient.connected) {
    global.socketClient.disconnect();
    logger.info('[lifecycle] WebSocket connection closed');
  }
  
  // 取消所有未完成的HTTP请求
  if (global.apiClient) {
    global.apiClient.cancelAllRequests();
    logger.info('[lifecycle] Pending HTTP requests cancelled');
  }
}

3. 临时文件清理

删除应用运行过程中创建的临时文件:

async beforeClose() {
  logger.info('[lifecycle] before-close: cleaning temporary files');
  
  const tempDir = path.join(app.getPath('temp'), 'electron-egg-app');
  
  try {
    await fs.promises.access(tempDir);
    await fs.promises.rm(tempDir, { recursive: true, force: true });
    logger.info(`[lifecycle] Temporary directory ${tempDir} cleaned up`);
  } catch (error) {
    if (error.code !== 'ENOENT') {
      logger.error('[lifecycle] Failed to clean temporary files', error);
    } else {
      logger.info('[lifecycle] No temporary files to clean');
    }
  }
}

4. 进程终止

确保所有衍生进程被正确终止:

async beforeClose() {
  logger.info('[lifecycle] before-close: terminating child processes');
  
  if (global.childProcesses && global.childProcesses.length > 0) {
    for (const proc of global.childProcesses) {
      if (!proc.killed) {
        proc.kill('SIGINT');
        logger.info(`[lifecycle] Terminated process ${proc.pid}`);
      }
    }
    
    // 等待进程退出
    await new Promise(resolve => setTimeout(resolve, 1000));
  }
}

窗口关闭行为配置

应用窗口的关闭行为直接影响退出流程。electron-egg 的窗口配置位于 electron/config/config.default.js,其中与退出相关的关键配置如下:

窗口配置示例

windowsOption: {
  title: 'electron-egg',
  width: 980,
  height: 650,
  minWidth: 400,
  minHeight: 300,
  webPreferences: {
    contextIsolation: false,
    nodeIntegration: true,
  },
  frame: true,
  show: true,
  icon: path.join(getBaseDir(), 'public', 'images', 'logo-32.png'),
}

单实例与多窗口退出策略

electron-egg 默认启用单实例锁定(singleLock: true),确保系统中只有一个应用实例在运行。在多窗口应用中,需区分"关闭当前窗口"和"退出应用"两种行为:

// 在主进程中
ipcMain.on('window-close', (event, windowId) => {
  const window = BrowserWindow.fromId(windowId);
  
  if (BrowserWindow.getAllWindows().length > 1) {
    // 关闭当前窗口
    window.close();
  } else {
    // 最后一个窗口,执行完整退出流程
    app.quit();
  }
});

高级退出场景处理

某些复杂应用可能需要处理更特殊的退出场景,如后台任务完成前阻止退出、多窗口状态同步等。

阻止退出的实现

在某些情况下(如文件正在保存),应用需要阻止退出并提示用户:

// 在渲染进程中
window.addEventListener('beforeunload', (e) => {
  // 取消事件
  e.preventDefault();
  // Chrome 需要设置 returnValue
  e.returnValue = '';
  
  // 显示确认对话框
  const result = confirm('有未保存的更改,确定要退出吗?');
  
  if (!result) {
    // 用户取消退出
    return false;
  } else {
    // 用户确认退出,继续关闭流程
    return true;
  }
});

强制退出机制

对于无响应的应用,提供强制退出选项是必要的。可通过托盘图标菜单实现:

// 在主进程中创建托盘菜单
const contextMenu = Menu.buildFromTemplate([
  { 
    label: '强制退出',
    click: () => {
      app.exit(0);
    }
  }
]);

退出流程的调试与日志

electron-egg 提供了完善的日志系统,可帮助开发者调试退出流程。日志配置位于 electron/config/config.default.js

logger: {
  level: 'INFO',
  outputJSON: false,
  appLogName: 'ee.log',
  coreLogName: 'ee-core.log',
  errorLogName: 'ee-error.log' 
}

关键日志点

在退出流程中添加详细日志,有助于追踪问题:

async beforeClose() {
  logger.info('[lifecycle] before-close: starting resource cleanup');
  
  try {
    // 数据保存逻辑
    logger.info('[lifecycle] before-close: data saved successfully');
    
    // 网络连接清理
    logger.info('[lifecycle] before-close: network connections closed');
    
    // 临时文件清理
    logger.info('[lifecycle] before-close: temporary files cleaned');
    
    logger.info('[lifecycle] before-close: resource cleanup completed');
  } catch (error) {
    logger.error('[lifecycle] before-close: cleanup failed', error);
  }
}

日志文件位置

日志文件默认存储在应用的数据目录中,不同平台的路径如下:

  • Windows: %APPDATA%\electron-egg\logs
  • macOS: ~/Library/Logs/electron-egg
  • Linux: ~/.config/electron-egg/logs

最佳实践与案例分析

企业级应用退出策略

企业级应用通常需要更严格的退出流程,以下是一个综合案例:

async beforeClose() {
  logger.info('[lifecycle] Enterprise-grade cleanup started');
  
  // 1. 保存用户会话状态
  await this.saveUserSession();
  
  // 2. 同步服务器数据
  await this.syncServerData();
  
  // 3. 清理临时文件
  await this.cleanTempFiles();
  
  // 4. 记录使用统计
  await this.sendUsageStats();
  
  // 5. 关闭数据库连接
  await this.closeDatabaseConnections();
  
  logger.info('[lifecycle] Enterprise-grade cleanup completed');
}

性能优化建议

  • 异步清理:所有清理操作应使用异步方式,避免阻塞退出流程
  • 超时控制:为每个清理步骤设置超时,防止无限等待
  • 并行执行:互不依赖的清理操作可并行执行,减少总耗时
  • 优先级排序:重要操作(如数据保存)应优先执行

框架内置退出相关资源

electron-egg 提供了多个与退出相关的资源文件,位于 public/images/example/ 目录,包含不同平台的界面示例:

Windows平台应用界面 macOS平台应用界面 Ubuntu平台数据库界面

这些示例展示了不同平台下的应用窗口布局,包括关闭按钮位置及退出相关的UI元素。

总结与扩展

应用退出策略是桌面应用开发中不可或缺的一环,良好的退出流程能够提升用户体验并保护数据安全。electron-egg 通过生命周期钩子机制,为开发者提供了灵活而强大的退出流程管理工具。

核心要点回顾

  1. 使用 before-close 钩子实现退出前资源清理
  2. 根据应用需求处理不同类型的资源(文件、网络、进程等)
  3. 合理配置窗口选项影响退出行为
  4. 实现必要的用户交互(如未保存提示)
  5. 完善日志系统,便于调试退出问题

扩展建议

  • 实现退出状态的持久化,支持应用重启后恢复之前状态
  • 添加退出动画,提升用户体验
  • 开发退出流程的单元测试,确保稳定性
  • 针对不同平台优化退出行为,遵循平台设计规范

通过本文介绍的方法,开发者可以在 electron-egg 框架下构建出健壮、用户友好的应用退出流程,为企业级桌面应用提供可靠的生命周期管理。

【免费下载链接】electron-egg A simple, cross platform, enterprise desktop software development framework 【免费下载链接】electron-egg 项目地址: https://gitcode.com/dromara/electron-egg

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值