应用事件系统
事件注册流程
应用事件在主进程启动时统一注册,由 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- 主进程入口