【问题标题】:While loop inside async function executes one extra time when condition is false当条件为假时,异步函数内的循环会额外执行一次
【发布时间】:2021-02-18 19:30:10
【问题描述】:

我正在使用 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

我的问题是:shinyRunningtrue 时,是什么导致这个while 循环额外执行一次?

如果您需要有关我的应用或整个 .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

【问题讨论】:

  • 这很奇怪,为什么要把异步函数放在while循环中?我在stackoverflow [javascript]中到处都看到过很多这样的问题。将异步代码放在同步循环代码中是非常糟糕的代码实践
  • 我是 JS 的初学者。这是我复制并粘贴的代码。我已经用@cuspymd 的建议更新了我的代码,现在我认为它工作得更好。我还删除了 while 循环。这和你的做法相似吗?

标签: javascript r shiny electron


【解决方案1】:

需要添加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')
            })
...

【讨论】:

  • 现在 while 只执行一次,但应用程序加载后不再执行。谢谢!
猜你喜欢
  • 2014-03-30
  • 1970-01-01
  • 1970-01-01
  • 2022-11-28
  • 2014-03-03
  • 1970-01-01
  • 1970-01-01
  • 2020-07-21
  • 1970-01-01
相关资源
最近更新 更多