一、为什么需要关注系统电源状态变化

开发Electron应用时,我们常常需要处理各种系统事件,比如窗口大小变化、网络状态切换等。但有一个容易被忽视却非常重要的场景——系统电源状态变化。想象一下,用户正在用你的Electron应用编辑重要文档,突然电脑进入休眠模式,如果没有正确处理电源事件,可能会导致数据丢失或功能异常。

电源状态变化主要包括以下几种情况:

  1. 系统休眠/睡眠(suspend)
  2. 系统唤醒(resume)
  3. 电池状态变化(比如从交流电切换到电池供电)
  4. 关机/重启(虽然Electron无法阻止,但可以尝试保存数据)

如果应用需要在后台执行重要任务(比如上传文件、同步数据),或者需要优化电池使用(比如游戏降低帧率),正确处理这些事件就非常关键。

二、Electron如何监听电源事件

Electron提供了powerMonitor模块来监听系统电源状态变化。这个模块是主进程(main process)专用的,渲染进程(renderer process)需要通过IPC与主进程通信来获取电源状态。

基础示例(技术栈:Electron + Node.js)

// 主进程代码(main.js)
const { app, powerMonitor } = require('electron');

// 监听系统即将进入休眠状态
powerMonitor.on('suspend', () => {
  console.log('系统即将休眠,赶紧保存数据!');
  // 这里可以触发数据保存逻辑
});

// 监听系统唤醒
powerMonitor.on('resume', () => {
  console.log('系统唤醒了,检查网络连接或恢复任务');
});

// 监听电源插拔(仅适用于有电池的设备,比如笔记本)
powerMonitor.on('on-ac', () => {
  console.log('切换到交流电源,可以放开性能限制了');
});

powerMonitor.on('on-battery', () => {
  console.log('切换到电池供电,建议降低功耗');
});

app.whenReady().then(() => {
  console.log('电源监控已启动');
});

渲染进程如何获取电源状态

由于powerMonitor只能在主进程使用,渲染进程可以通过ipcRenderer与主进程通信:

// 渲染进程代码(renderer.js)
const { ipcRenderer } = require('electron');

// 向主进程请求当前电源状态
ipcRenderer.invoke('get-power-status').then(status => {
  console.log('当前电源状态:', status);
});

// 监听主进程主动推送的电源变化
ipcRenderer.on('power-status-changed', (event, status) => {
  console.log('电源状态变化:', status);
});

对应的主进程IPC处理:

// 主进程补充代码(main.js)
const { ipcMain } = require('electron');

ipcMain.handle('get-power-status', () => {
  return powerMonitor.isOnBatteryPower() ? 'battery' : 'ac';
});

// 可以在电源事件回调里主动推送
powerMonitor.on('on-ac', () => {
  mainWindow.webContents.send('power-status-changed', 'ac');
});

powerMonitor.on('on-battery', () => {
  mainWindow.webContents.send('power-status-changed', 'battery');
});

三、实际应用场景与优化策略

场景1:数据持久化

在系统休眠前,应用应该保存未提交的数据。例如,一个笔记应用可以这样实现:

powerMonitor.on('suspend', async () => {
  const unsavedNotes = getUnsavedNotes(); // 获取未保存的笔记
  if (unsavedNotes.length > 0) {
    await saveToTempFile(unsavedNotes);   // 写入临时文件
    console.log('数据已备份');
  }
});

场景2:功耗敏感型应用

如果应用是视频播放器或游戏,可以在电池模式下降低性能:

let isOnBattery = powerMonitor.isOnBatteryPower();
let frameRate = isOnBattery ? 30 : 60; // 电池模式下限制帧率

powerMonitor.on('on-battery', () => {
  frameRate = 30;
  console.log('切换到省电模式');
});

powerMonitor.on('on-ac', () => {
  frameRate = 60;
  console.log('切换到高性能模式');
});

场景3:网络状态恢复

系统唤醒后,网络连接可能需要时间恢复:

powerMonitor.on('resume', () => {
  setTimeout(() => {
    checkNetworkConnection(); // 延迟检查网络
  }, 3000);
});

四、注意事项与兼容性问题

  1. 平台差异

    • Windows/macOS支持suspend/resume事件
    • Linux行为可能不一致,建议测试目标发行版
  2. powerMonitor必须在app.whenReady()后调用,否则会报错

  3. 避免阻塞主进程
    电源事件的回调函数应当快速执行,长时间运行的任务应该放到独立进程或使用setImmediate

  4. 测试策略

    • 开发阶段可以模拟电源事件:
      // 测试代码:模拟电源事件
      process.nextTick(() => {
        powerMonitor.emit('suspend');
      });
      
  5. 与系统休眠阻止的配合
    如果需要阻止系统休眠(比如视频播放),可以用powerSaveBlocker

    const { powerSaveBlocker } = require('electron');
    const id = powerSaveBlocker.start('prevent-display-sleep');
    console.log(powerSaveBlocker.isStarted(id)); // true
    

五、总结

正确处理电源事件能让Electron应用更健壮,特别是在移动设备上。关键点包括:

  • 使用powerMonitor模块监听休眠/唤醒/电源变化
  • 主进程与渲染进程通过IPC通信
  • 针对不同场景优化(数据持久化、性能调整)
  • 注意平台差异和性能影响

良好的电源管理不仅能提升用户体验,还能节省电量——这对笔记本用户尤其重要。