【问题标题】:How to fix race condition between Promise resolving on win.loadFile() and app.on('browser-window-created') event如何修复 Promise 解决 win.loadFile() 和 app.on('browser-window-created') 事件之间的竞争条件
【发布时间】:2019-05-02 22:58:28
【问题描述】:

我正在开发一个 Electron 应用程序,其中一个模块创建一个 BrowserWindow 并且其他模块(它们都在主进程中)可以在窗口完全加载后访问窗口(包括在此期间窗口已关闭的情况)。

我正在 macOS 上使用 Electron 5.0.0。

到目前为止,这是我想出的一个简化版本:

// module mainWindow.js

const { BrowserWindow } = require('electron')
let ready = null

const createWindow = () => {
  console.log('creating window')  
  return new Promise((resolve) => {  
    let win = new BrowserWindow({
      show: false,
    })
    win.on('closed', () => {
      ready = null
    })
    win.loadFile('renderer.html').then(() => {
      win.show()
      resolve(win)
      console.log('window.load resolved')    
    })
    console.log('window id', win.id)        
}

const get = (create) => {
  console.log('get')
  if (ready) {
    console.log('ready')
    return ready
  } else {
    console.log('not ready')
    if (create) {
      console.log('creating')
      ready = createWindow()
      return ready
    } else {
      console.log('rejecting')
      return Promise.reject()
    }
  }
}

exports.get = get


// some other module

const win = require('mainWindow.js')
win.get(true).then((win) => { /* ... */ })


// yet another module

const { app } = require('electron')
const win = require('mainWindow.js')
app.on('browser-window-created', () => {
  console.log('app.browser-window-created')
  win.get(false).then((win) => {
    log('got it')
    // ...
  }, () => {
    log('there is no window')
  })
})

在我看来,createWindow() 应该返回一个未解决的承诺(然后存储在ready异步创建窗口之前。但我的控制台显示:

get
not ready
creating
creating window
app.browser-window-created
get
not ready
rejecting
window id 1
there is no window
window.load resolved

有没有办法解决这个问题?

【问题讨论】:

    标签: javascript node.js electron


    【解决方案1】:

    问题似乎是事件是同步触发的,因此它在函数执行完成之前运行,而ready = 尚未运行。要解决这个问题,您必须推迟创建窗口:

      return new Promise((resolve, reject) => {
       setTimeout(() => {
         //...
       });
      });
    

    get 内分配给ready 时,您也可以使用另一个promise 来推迟这一点:

      ready = Promise.resolve().then(createWindow);
    

    或者,您可以在创建窗口之前重新分配ready,因为您必须从回调中公开resolve

      let resolve;
      ready = new Promise(it => resolve = it);
    
      // create window ...
      // somewhen ...
      resolve(win);
    

    【讨论】:

    • 谢谢!我花了几个小时试图解决这个问题(你的第二个解决方案对我来说就像一个魅力)。
    【解决方案2】:

    你的问题是 let win = new BrowserWindow 立即触发 'browser-window-created' 事件,因此在它的回调中你找不到任何待处理的 Promise。

    所以我建议你重构代码。

    例如app.on('browser-window-created')可以用来获取创建的BrowserWindow。将监听器添加到 BrowserWindow 的 webContents 的 'did-finish-load',您只需完全获得与返回的 Promise 相同的回调(loadFile 解析该事件)

    app.on('browser-window-created', (event, window) => {
      console.log('app.browser-window-created')
      window.webContents.on('did-finish-load', () => {
        console.log('got it')
        // ...
      })
      window.webContents.on('did-fail-load', () => {
        console.log('there is no window')
      })
    })
    

    【讨论】:

      猜你喜欢
      • 2019-09-19
      • 2016-01-06
      • 2016-11-16
      • 2020-08-08
      • 1970-01-01
      • 2018-01-19
      • 1970-01-01
      • 2013-10-11
      • 2013-09-06
      相关资源
      最近更新 更多