即使所有退出事件成功触发,Electron 应用程序也会挂起

Posted

技术标签:

【中文标题】即使所有退出事件成功触发,Electron 应用程序也会挂起【英文标题】:Electron app hangs on quitting even though all quit events successfully fired 【发布时间】:2019-06-28 18:00:20 【问题描述】:

一段时间以来,我一直在尝试调试我们的电子应用程序的问题,但它变得相当困难。

问题:间歇性地,当使用退出快捷键(cmd+Q)时,应用程序 UI 成功消失,但它停留在菜单栏(mac)/通知 try(win)并显示悬停时的死亡沙滩球。

我必须去活动监视器才能真正强制关闭它 app not responding

这只发生在打包的生产应用中,而不是在开发模式下。在查看日志时,似乎所有的退出事件都被正确命中了。

app.on('window-all-closed', () => 
  log.info('All windows closed');

  if (process.platform != 'darwin') 
    app.quit();
  
);
// Logs to help nail down quit failures
app.on('will-quit', () => log.info('App will quit'));
app.on('quit', () => log.info('App is quitting'));

app.on('before-quit', async () => 
 log.info('Attempting to quit app');

log.log 的尾部

[2019-02-04 14:29:34.543] [info] electron: message received: windows-info
[2019-02-04 14:29:35.831] [info] Attempting to quit app
[2019-02-04 14:29:35.919] [info] stopping mouse tracking
[2019-02-04 14:29:36.073] [info] App will quit
[2019-02-04 14:29:36.079] [info] App is quitting
[2019-02-04 14:29:36.127] [info] ???? mac binary: main.swift:49 : sendPayload(messageToSend:): "type":"will-close-expectedly"

[2019-02-04 14:29:36.128] [info] electron: message received: will-close-expectedly
[2019-02-04 14:29:36.130] [info] daemon binary /Applications/Loom.app/Contents/Resources/app.asar.unpacked/dist/binaries/loom-mac-recorderproduction exited
[2019-02-04 14:29:37.555] [error] No menubar present
[2019-02-04 14:29:37.676] [error] No menubar present
[2019-02-04 14:29:39.537] [error] No menubar present
[2019-02-04 14:29:39.675] [error] No menubar present
[2019-02-04 14:29:41.653] [error] No menubar present
[2019-02-04 14:29:41.790] [error] No menubar present

正如您从日志中看到的,所有退出事件都以正确的顺序触发,但应用程序仍停留在 mac 菜单栏中。发生的一件有趣的事情是[error] No menubar present。每当我尝试单击菜单栏中的图标时,就会出现这种情况。它应该在尝试隐藏应用程序菜单时抛出。 这是有问题的菜单栏:https://github.com/maxogden/menubar。

这就是成功退出日志的样子

019-02-04 14:52:36.722] [info] Attempting to quit app
[2019-02-04 14:52:36.740] [info] stopping mouse tracking
[2019-02-04 14:52:36.868] [info] App will quit
[2019-02-04 14:52:36.874] [info] App is quitting
[2019-02-04 14:52:36.887] [info] ???? mac binary: main.swift:49 : sendPayload(messageToSend:): "type":"will-close-expectedly"

[2019-02-04 14:52:36.889] [info] daemon binary /Applications/LoomStaging.app/Contents/Resources/app.asar.unpacked/dist/binaries/loom-mac-recorderstaging exited

有什么办法可以深入了解导致应用程序挂起的原因,因为在主进程中似乎没有抛出任何错误,只是所有 UI 元素都消失但进程仍然存在的这种幽灵状态。有没有办法更深入地了解正在发生的事情/挂起的位置。

另一个有趣的地方是,每当我们在更新时执行 quitAndInstall(使用 electron-builder),如果前面提到的菜单栏是 hidden,那么我们几乎总是会遇到这种奇怪的挂起状态,但是当菜单栏可见并且我们启动了一个quitAndInstall,它工作正常。

【问题讨论】:

希望您能找到解决这个有趣问题的方法。它可能与您的情况无关,但有时我发现当我的主进程在退出时挂起时,这是因为我有一个仍然连接的调试器正在监听其中一个进程。一旦我找到并杀死调试器,我的主进程就可以退出。另一个建议是检查哪些侦听器正在侦听电子应用对象上的事件,它可能会深入了解问题的根源 【参考方案1】:

我用准系统示例创建了测试repo。

在我的机器上它工作正常(我在window-all-closed 事件中删除了对process.platform 的检查,但我在有和没有这些检查的情况下进行了测试 - 双向工作):

const  menubar  = require('menubar');
const  app, Menu, Tray, autoUpdater, dialog  = require('electron');

autoUpdater.setFeedURL(`https://update.electronjs.org/sanperrier/menubar-test/$process.platform-$process.arch/$app.getVersion()`);

autoUpdater.on('update-not-available', () => 
    dialog.showMessageBox(
        title: "No available updates",
        message: `No available updates\ncurrent version: $app.getVersion()`
    );
);

autoUpdater.on('update-available', () => 
    dialog.showMessageBox(
        title: "Update is downloading",
        message: `Update is downloading\ncurrent version: $app.getVersion()`
    );
);

autoUpdater.on('update-downloaded', async (e, notes, name) => 
    await dialog.showMessageBox(
        title: "Update downloaded",
        message: `Update downloaded\ncurrent version: $app.getVersion()\nnew version: $name`,
        detail: notes
    );

    autoUpdater.quitAndInstall();
);

app.on('ready', () => 
    const tray = new Tray(require.resolve('menubar/assets/IconTemplate.png'));
    const contextMenu = Menu.buildFromTemplate([
        
            label: `Check for updates and install (current: $app.getVersion())`,
            type: 'normal',
            click: () => autoUpdater.checkForUpdates()
        ,
        
            label: 'Close window',
            type: 'normal',
            click: () => mb.window?.close()
        ,
        
            label: 'Exit',
            type: 'normal',
            click: () => app.quit()
        
    ]);
    tray.setContextMenu(contextMenu);

    const mb = menubar( tray );
);

app.on('window-all-closed', e => 
    console.log('window-all-closed');

    // if (process.platform != 'darwin') 
        app.quit();
    // 
);

app.on('before-quit', () => console.log('before-quit'));
app.on('will-quit', () => console.log('will-quit'));
app.on('quit', async () => console.log('quit'));

工作正常。

可能的问题:

    旧版电子 也许在window-all-closed 中为darwin 平台调用app.quit() 会有所帮助 我在menubar 来源中搜索了“没有菜单栏”,但一无所获,因此此错误源于您的代码或第 3 方代码。或者可能是旧版本的menubar

请澄清一下,“菜单栏是hidden”是什么意思。

作为一种解决方法,您可以尝试将app.exit(0) 添加到quit 事件处理程序。我不确定它会破坏autoUpdate.quitAndInstall()。我用这样的代码对其进行了测试:app.on('quit', () => console.log('quit'); app.exit(0); ),它运行良好:

$ menubar-test.app/Contents/MacOS/menubar-test 
2020-08-08 13:35:20.689 menubar-test[62834:6522941] Download completed to: file:///Users/sanperrier/Library/Caches/com.electron.menubar-test.ShipIt/update.aaHFVTv/menubar-test-darwin-x64-1.1.11.zip
before-quit
will-quit
quit

应用下载更新并重新启动(已安装更新)。

希望这会有所帮助。随意 fork 我的 repo 并使用它来确定问题的根本原因。

【讨论】:

以上是关于即使所有退出事件成功触发,Electron 应用程序也会挂起的主要内容,如果未能解决你的问题,请参考以下文章

即使响应为 200(成功),也会调用 Axios Catch

Electron生命周期

Electron之Main有什么关系?

Electron Windows增加托盘悬浮框功能

Android Geofences (Location Services) - 如何触发应用内事件

Electron页面加载事件发生顺序