如何解决win.loadFile()和app.on('浏览器窗口创建的')事件上的Promise解决之间的竞争状况

时间:2019-05-02 13:58:48

标签: javascript node.js electron

我正在开发一个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

有什么办法可以解决这个问题?

2 个答案:

答案 0 :(得分:1)

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

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

您还可以在分配给ready内的get时使用另一个诺言:

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

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

  let resolve;
  ready = new Promise(it => resolve = it);

  // create window ...
  // somewhen ...
  resolve(win);

答案 1 :(得分:0)

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

所以我建议您重组代码。

例如app.on('browser-window-created')可用于获取创建的BrowserWindow。将监听器添加到'did-finish-load'的BrowserWindow的webContents中,您将获得与返回的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')
  })
})