Skip to content

应用事件系统

事件注册流程

应用事件在主进程启动时统一注册,由 app-events.js 模块负责:

javascript
const { registerAppEvents } = require('./apps/app-events');

// 在 app.whenReady() 之后注册
app.whenReady().then(() => {
  registerAppEvents();
  // ...其他初始化
});

核心应用事件

before-quit

应用退出前触发,用于清理资源。

javascript
app.on('before-quit', async () => {
  logger.info('应用程序退出before-quit');

  // 关闭本地服务器
  const localServer = LocalServer.getInstance();
  await localServer.stop();

  // 清理 IPC 处理器
  IpcManager.removeHandlers();

  // 清理错误捕获系统
  const errorManager = ErrorCaptureManager.getInstance();
  errorManager.cleanup();

  // 停止日志清理定时任务
  LoggerClean.getInstance().stopScheduledCleanup();
});

清理内容:

  • 关闭本地 HTTP 服务器
  • 移除所有 IPC 处理器
  • 清理错误捕获系统
  • 停止日志清理定时任务

window-all-closed

所有窗口关闭时触发。

javascript
app.on('window-all-closed', () => {
  // macOS 上通常保持应用运行
  if (process.platform !== 'darwin') {
    app.quit();
  }
});

平台差异:

  • Windows/Linux: 所有窗口关闭后退出应用
  • macOS: 保持应用运行,直到用户明确退出

activate

应用激活时触发(主要用于 macOS)。

javascript
app.on('activate', () => {
  // macOS 上点击 Dock 图标时,如果没有窗口则创建新窗口
  if (BrowserWindow.getAllWindows().length === 0) {
    createWindow();
  }
});

使用场景:

  • macOS 上点击 Dock 图标
  • 应用从后台切换到前台
  • 所有窗口被关闭但应用仍在运行

ready

应用初始化完成,准备创建窗口。

javascript
app.whenReady().then(() => {
  // 注册全局事件
  registerAppEvents();

  // 初始化错误捕获系统
  const errorManager = ErrorCaptureManager.getInstance();
  errorManager.initialize();

  // 注册 IPC 处理器
  await IpcManager.registerHandlers();

  // 创建主窗口
  const win = createWindow();

  // 添加托盘菜单
  addTrayMenu(win, updateHandler, FloatingBallService);

  // 启动日志清理任务
  LoggerClean.getInstance().startScheduledCleanup();
});

开发环境特殊处理

优雅退出

开发环境下需要处理来自构建工具的退出信号:

javascript
function setupDevEnvironment() {
  if (process.platform === 'win32') {
    // Windows 平台监听 message 事件
    process.on('message', (data) => {
      if (data === 'graceful-exit') {
        app.quit();
      }
    });
  } else {
    // Unix 平台监听 SIGTERM 信号
    process.on('SIGTERM', () => {
      app.quit();
    });
  }
  logger.info('开发环境配置完成');
}

触发场景:

  • 开发服务器重启
  • 手动停止开发服务器
  • 构建工具发送退出信号

窗口事件

ready-to-show

窗口准备好显示时触发,用于避免闪烁。

javascript
win.once('ready-to-show', () => {
  win.show();

  // 检查更新(生产环境)
  if (app.isPackaged && shouldCheckForUpdates) {
    updateHandler.checkUpdate();
  }
});

will-navigate

窗口即将导航到新页面时触发。

javascript
win.webContents.on('will-navigate', (event, url) => {
  // 可以在这里阻止或允许导航
  if (!isAllowedUrl(url)) {
    event.preventDefault();
    logger.warn('导航被阻止:', url);
  }
});

did-fail-load

页面加载失败时触发。

javascript
win.webContents.on('did-fail-load', (event, errorCode, errorDescription) => {
  logger.error('页面加载失败:', { errorCode, errorDescription });
  // 加载错误页面
  win.loadFile('error.html');
});

进程通信事件

IPC 事件

通过 ipcMain 注册的 IPC 事件处理器:

javascript
// 处理渲染进程发送的消息
ipcMain.on('channel-name', (event, data) => {
  // 处理数据
  event.reply('response-channel', result);
});

// 处理需要返回值的调用
ipcMain.handle('channel-name', async (event, data) => {
  // 异步处理
  return result;
});

详见 IPC通信文档

系统事件

电源管理

javascript
const { powerMonitor } = require('electron');

// 系统挂起
powerMonitor.on('suspend', () => {
  logger.info('系统即将挂起');
  // 保存状态
});

// 系统恢复
powerMonitor.on('resume', () => {
  logger.info('系统已恢复');
  // 恢复操作
});

网络状态

javascript
const { net } = require('electron');

// 检查网络连接
if (net.isOnline()) {
  // 在线操作
} else {
  // 离线操作
}

事件执行顺序

应用启动时的事件执行顺序:

1. app.on('ready') 或 app.whenReady()

2. registerAppEvents() - 注册全局事件

3. ErrorCaptureManager.initialize() - 初始化错误捕获

4. IpcManager.registerHandlers() - 注册 IPC 处理器

5. createWindow() - 创建主窗口

6. win.once('ready-to-show') - 窗口准备就绪

7. 应用正常运行

8. app.on('before-quit') - 应用退出前

9. 清理资源并退出

最佳实践

1. 使用 once 避免重复监听

javascript
// 只监听一次
win.once('ready-to-show', () => {
  win.show();
});

2. 及时清理事件监听器

javascript
// 保存监听器引用
const handler = (event, data) => {
  /* ... */
};
ipcMain.on('channel', handler);

// 清理时移除
ipcMain.removeListener('channel', handler);

3. 错误处理

javascript
app.on('some-event', () => {
  try {
    // 事件处理逻辑
  } catch (error) {
    logger.error('事件处理失败:', error);
  }
});

4. 异步操作使用 async/await

javascript
app.on('before-quit', async () => {
  try {
    await performCleanup();
  } catch (error) {
    logger.error('清理失败:', error);
  }
});

相关文件

  • packages/main/src/apps/app-events.js - 应用事件注册
  • packages/main/src/apps/app-initializer.js - 应用初始化
  • packages/main/src/main.js - 主进程入口

相关文档

基于 MIT 许可发布