Electron 窗口卡顿问题的处理

最近发现使用 Electron 做跨平台桌面软件开发是一种很有意思的体验:只要你熟悉最基础的前端知识,在配合 Electron Document 就可以开发跨平台的桌面软件,想想还是很香的。

Electron 在其 官方 demo 中提供了常见桌面软件大部分基础性事件处理模式,包括:BrowserWindow 的创建及切换、系统菜单管理、main process 以及 renderer process 之间的通信、系统托盘处理、消息通知体系等。如果想要快速了解并掌握 Electron 开发的话,相信这应该是最好的教材。

electron api demo

electron api demo

然而,在官方提供的 demo 中有两段个人认为处理的并不是特别好的代码。首先是创建窗口时对 close 事件的响应:

function createWindow() {
   mainWindow = new BrowserWindow(windowOptions)
   //.....
   mainWindow.on('closed', () => {
      mainWindow = null
    })
}

按照 Electron 提供的文档中对 close 的说明:close 事件 会在当前窗口关闭时触发。上面给出的代码中,对窗口的关闭事件响应为:将窗口对象置空。这种处理方式看似没有问题,但在 macOS 系统中窗口被关闭时,一般情况下的默认操作并不是停止运行软件,而是在 Dock 中保留软件以备用户再次点击时恢复。为了解决这个问题,官方 demo 中又引入了 activate 事件,其代码处理方式为:

app.on('activate', () => {
    if (mainWindow === null) {
      createWindow()
    }
})

每次用户点击窗口关闭按钮时,将窗口对象释放,再点击时又重新创造一次窗口。这样的处理方式实在不敢苟同。想象一下,如果创建窗口的过程较为复杂(eg:判断登录状态、执行部分逻辑判断、网络请求之后再做业务逻辑等等),在体验上就会出现问题。实际上,官方提供的 demo 运行起来,在 macOS 系统中重复关闭再打开时,就会出现非常明显的「卡顿」情况,而卡顿的原因自然是因为每次窗口重新创建时,系统开销是很大的

那么,假如我们在窗口关闭时,只是将其隐藏处理呢?

mainWindow.on('close', function (event) {
  event.preventDefault()
  mainWindow.hide()
})

如果 mainWindow 对象没有被销毁,在 activate 事件处就可以这样做:

app.on('activate', () => {
  if (mainWindow && !mainWindow.isDestroyed()) {
    mainWindow.show()
    mainWindow.focus()
  }
})

实际上,window 对象一直存在与内存中直至 app 被销毁,并不是最佳实践。为了让代码能够更加严谨,可以深挖 Electron 的文档,在其中发现了 before-quit 事件。于是,修改上述的代码之后,最终的处理方式变成:

app.on('before-quit', function () {
    app.quitting = true
})

mainWindow.on('close', function (event) {
  if (app.quitting) {
    mainWindow = null // 如果当前操作确实是需要关闭窗口的话,就将其置空
  } else {
     event.preventDefault()
     mainWindow.hide()
  }
 })

至于为什么一定要这样做,就留给大家去猜吧!能看懂的人,会懂。

版权声明:本站所有内容,未经书面授权禁止一切形式的转载、摘录及摘抄,违者依法追究其相关责任。

相关文章