skip to Main Content

Considering the renderer and main are handling promises, will the code below force the process to become synchronous if openFile() is not also set to async await?

contextBridge.exposeInMainWorld('myAPI',
  {
    openFile: () => ipcRenderer.invoke('dialog:openFile'),
    ...

If the code below is absolutely unnecessary, can somebody explain why async await can be omitted like in the code above?

contextBridge.exposeInMainWorld('myAPI',
  {
    openFile: async () => await ipcRenderer.invoke('dialog:openFile'),
    ...

FWIW:

// renderer.js

el.addEventListener('click', async ()=>{
  const filePath = await window.myAPI.openFile()
  el.textContent = filePath
})


// main.js

ipcMain.handle('dialog:openFile', async ()=>{
  const { canceled, filePaths } = await dialog.showOpenDialog()
  if (!canceled) return filePaths[0]
})

2

Answers


  1. As per the docs:

    ipcRenderer.invoke(channel, …args):
    Returns Promise – Resolves with the response from the main process.

    which suggests that the code without async-await will work correctly since ipcRenderer.invoke itself returns a Promise. When you omit async-await, you’re essentially returning the Promise returned by ipcRenderer.invoke directly. This means the async-await in your event listener will still handle the returned Promise correctly, as it is expecting a Promise.

    In summary, the use of async-await is not necessary and not using it will make your code concise and perform the same way as with it in this case because the function is returning a Promise directly, and the calling code (event listener) is already handling it with async-await.

    Login or Signup to reply.
  2. It can be omitted because either way you are returning a Promise. In the second example, you are creating an async function that waits for ipcRenderer.invoke()‘s promise to resolve, then resolves itself.

    contextBridge.exposeInMainWorld('myAPI',
      {
        openFile: async () => await ipcRenderer.invoke('dialog:openFile'), // () => Promise<...>
        ...
    

    The async keyword causes the function to return a Promise, rather than a value, so as ipcRenderer.invoke is async, and therefore already returns a Promise, there is no need to use the above syntax, which essentially wraps the ipcRenderer promise by itself.

    This is what makes the first example functionally equivalent to the second. Both functions supply a Promise, and can both be awaited.

    contextBridge.exposeInMainWorld('myAPI',
      {
        openFile: () => ipcRenderer.invoke('dialog:openFile'), // () => Promise<...>
        ...
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search