首页 > 解决方案 > 当条件为假时,异步函数内的循环会额外执行一次

问题描述

我正在使用 Electron 打包一个 R Shiny 应用程序。它在我的电脑和我测试过的大多数电脑上都能正常工作。但是,在某些情况下它会崩溃(通常在速度较慢的计算机中)。我不熟悉 Javascript,我试图了解我正在使用的 JS 代码中发生了什么。

经过一段时间试图找出导致崩溃的原因后,我注意到只有在我的应用程序尚未显示时才应该执行的 while 循环实际上又执行了一次。我怀疑这可能会导致问题(尽管我不确定)。以下是我在电子应用程序准备好时运行的内容。


app.on('ready', async () => {
  let shinyRunning = false
  let i = 1

  loadingSplashScreen = createSplashScreen('loading')
  mainWindow = createWindow()

  try {
    rShinyProcess = execa(NODER,
      ['-e', 'rbingo::launch_app(options = list(port = ' + srv.address().port + '))'], {
      env: {
        // Necessary for letting R know where it is and ensure we're not using another R
        'WITHIN_ELECTRON': 'T', // can be used within an app to implement specific behaviour
        'RHOME': rResources,
        'R_HOME_DIR': rResources,
        'R_LIBS': path.join(rResources, "library"),
        'R_LIBS_USER': path.join(rResources, "library"),
        'R_LIBS_SITE': path.join(rResources, "library"),
        'R_LIB_PATHS': path.join(rResources, "library")
        }
      })
    } catch {
       console.log(new Date().toISOString() + ':rshinyprocess execa catched')
       console.log(e)
    }
    
    mainWindow.loadURL('http://127.0.0.1:' + srv.address().port);
    
    try {
        while(!shinyRunning) {
            const wait_res = await waitFor(1000);
            console.log(new Date().toISOString() + ': Trying to connect...' + i)
            i += 1
            console.log('shinyRunning status: ' + shinyRunning)
            
            mainWindow.webContents.executeJavaScript('window.Shiny.shinyapp.isConnected()', true)
              .then((result) => {
                    shinyRunning = true
                    mainWindow.show()
                    loadingSplashScreen.hide()
                    loadingSplashScreen.close()
                    console.log(new Date().toISOString() + ': Successfully connected to the app')
            })
              .catch((result) => {
            })
        }
    } catch (e) {
        console.log(new Date().toISOString() + ': Error catched while trying to load the app.')
    }

    // Emitted when the window is closed.
    mainWindow.on('closed', function () {
        console.log(new Date().toISOString() + ': mainWindow.closed()')
        cleanUpApplication()
    })

    mainWindow.webContents.on('did-fail-load', (event, code, desc, url, isMainFrame) => {
      console.log(new Date().toISOString() + ': DID FAIL LOAD - ', code, desc, url, isMainFrame);
    });
})

23:56:38.475 > Application Started
2020-11-06T02:56:38.489Z: Listening on port 49271
2020-11-06T02:56:39.593Z: Trying to connect...1
shinyRunning status: false
2020-11-06T02:56:40.594Z: Trying to connect...2
shinyRunning status: false
2020-11-06T02:56:41.594Z: Trying to connect...3
shinyRunning status: false
2020-11-06T02:56:42.594Z: Trying to connect...4
shinyRunning status: false
2020-11-06T02:56:42.949Z: Successfully connected to the app 
2020-11-06T02:56:43.594Z: Trying to connect...5             <------ THIS SHOULDN'T BE HERE
shinyRunning status: true                                   <------ THIS SHOULDN'T BE HERE

我的问题是:shinyRunning是什么导致这个 while 循环在什么时候多执行一次true

如果您需要有关我的应用程序或整个 .js 文件的更多信息,我也可以分享。

谢谢,托马斯

PS: waitFor只是

function waitFor(miliseconds) {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve('resolved');
    }, miliseconds);
  });
}

编辑:

感谢@cuspymd 的回答和@syarul 的评论。

我已经更新了代码,现在我不再使用 while 循环,并且控制台看起来更好。


...

    mainWindow.loadURL('http://127.0.0.1:' + srv.address().port);
    
    try {
        await mainWindow.webContents.executeJavaScript('window.Shiny.shinyapp.isConnected()', true)
            .then((result) => {
                mainWindow.show()
                loadingSplashScreen.hide()
                loadingSplashScreen.close()
                console.log(new Date().toISOString() + ': Successfully connected to the app')
                shinyRunning = true
        })
            .catch((result) => {
        })  
        
    } catch (e) {
        console.log(new Date().toISOString() + ': Error catched while trying to load the app.')
    }

...

11:02:51.653 > Application Started
2020-11-06T14:02:51.668Z: Listening on port 63065
2020-11-06T14:02:56.079Z: Successfully connected to the app

标签: javascriptrshinyelectron

解决方案


您需要添加await以等待执行结果window.Shiny.shinyapp.isConnected()

...
            await mainWindow.webContents.executeJavaScript('window.Shiny.shinyapp.isConnected()', true)
              .then((result) => {
                    shinyRunning = true
                    mainWindow.show()
                    loadingSplashScreen.hide()
                    loadingSplashScreen.close()
                    console.log(new Date().toISOString() + ': Successfully connected to the app')
            })
...

推荐阅读