38

In my main process I create a renderer window:

var mainWindow = new BrowserWindow({
    height: 600,
    width: 800,
    x: 0,
    y: 0,
    frame: false,
    resizable: true
});
mainWindow.openDevTools();
mainWindow.loadURL('file://' + __dirname + '/renderer/index.html');

Then I want to communicate with it in some way:

mainWindow.webContents.send('message', 'hello world');

However the main window doesn't receive this message because it isn't fully done being created at the time I attempt to send it.

I have temporarily solved this by wrapping the latter code in a setTimeout() but that is most definitely not the right way to resolve a race condition.

Is there a callback for when the main window is ready? I tried the 'ready-to-show' event mentioned in the docs but it did not work.

Joey
  • 10,504
  • 16
  • 39
  • 54

7 Answers7

40

A listener on "mainWindow" doesn't worked for me. I used instead "mainWindow.webContents".

mainWindow.webContents.once('dom-ready', () => {});
Besa
  • 453
  • 4
  • 4
  • I think it's better to wait for `did-finish-load` not just `dom-ready`. I guess that `dom-ready` will fire before resources have been loaded: included script files! And so perhaps it's not safe to send yet, if the script that does the listening hasn't loaded yet. – ChrisW Sep 03 '22 at 08:50
12

Have a look at the did-finish-load event mentioned in the Electron browser-window documentation.

mainWindow.once('did-finish-load', () => {
   // Send Message
})

There seems to be a dom-ready event too.

Michael
  • 1,477
  • 4
  • 18
  • 27
  • 2
    Renderer window is not ready at this point. It can not even receive messages. – Steffan Oct 10 '18 at 22:49
  • @Steffan Could you elaborate a bit more, why window is not ready in `did-finish-load`? Electron Docs say, the event is emitted when `onload` event was dispatched. So I would assume, the page is fully loaded. PS I need to know, when it is safe to add eventlisteners in the browser `window` (like for `postMessage`) – ford04 May 27 '19 at 10:14
  • @ford04 I am actually not 100% sure why, but I could not get the DOM elements with it. But using mainWindow.webContents.once('dom-ready', () => {}) did also work with the DOM elements. I guess it is because the window is actually ready, but it as not yet rendered the content. – Steffan May 28 '19 at 15:08
  • Beware of tracking failures as well 'did-fail-load' – Eric Burel Aug 24 '21 at 15:59
  • @Steffan In [my answer](https://stackoverflow.com/a/73590779/49942) I didn't see or create a scenario where `did-finish-load` happens before `dom-ready`. Are you saying that you are seeing `dom-ready` happens after `did-finish-load`? – ChrisW Sep 03 '22 at 10:05
11

not mentioned in the previous answers, loadURL returns a promise that resolves at the same time the 'did-finish-load' event is fired; i.e., they're essentially equivalent, except one's a promise, and the other's a callback.

junvar
  • 11,151
  • 2
  • 30
  • 46
10

Check this: https://github.com/electron/electron/blob/master/docs/api/web-contents.md

You can use this event to know if your windows is ready in you main.js [CASE 1], but if want to know when your page is full loaded you should add an event in your index.html [CASE 2] and then you can attach a function that send a message to his parent Main.js telling him, he is ready, using IPCrenderer and IPCmain

CASE 1

main.js:

mainWindows.webContents.on('did-finish-load',WindowsReady);

function WindowsReady() {
    console.log('Ready');
}

CASE 2

html:

<script>
const {ipcRenderer} = require('electron');
document.addEventListener('DOMContentLoaded',pageLoaded);

 function pageLoaded(){
     alert('The page is loade');
     ipcRenderer.send('Am_I_Ready',"Im ready");
 }
</script>

Main.js:

const {ipcMain} = electron;

ipcMain.on('Am_I_Ready', doSomething)

function doSomething(){
  console.log('Everything is ready.');
}
Pete
  • 1,305
  • 1
  • 12
  • 36
Juan Sanchez
  • 543
  • 7
  • 14
  • Why do you think the extra code in CASE 2 is necessary? It seems to me that "to know when your page is full loaded" it's enough to wait for the `did-finish-load` event. – ChrisW Sep 03 '22 at 08:23
7

Use mainWindow.webContents like this:

mainWindow.webContents.on('did-finish-load', () => {
  mainWindow.webContents.send('message', 'hello world');
}
LuisZuluaga
  • 145
  • 2
  • 7
  • This should be marked as the answer. Just used it in my code and it works perfectly. This will allow me to remove jQuery onload. – raddevus Sep 15 '20 at 15:25
2

I tried the following code in my app

    window.webContents.once("did-finish-load", () => {
      console.log("did-finish-load");
    });

    window.webContents.once("dom-ready", () => {
      console.log("dom-ready");
    });

    window.once("ready-to-show", () => {
      console.log("ready-to-show");
    });

This is after loading an index.html from local file system:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Hi mom</title>
  <script defer src="renderer.js"></script></head>
  <body>
    <div id="renderer"></div>
  </body>
</html>

According to the console.log output they fired in the following sequence:

dom-ready
ready-to-show
did-finish-load

Therefore did-finish-load is probably the one to wait for -- because it's the latest therefore presumably the most-fully-loaded.

Also the API documentation for webContents.send includes this example:

// In the main process.
const { app, BrowserWindow } = require('electron')
let win = null

app.whenReady().then(() => {
  win = new BrowserWindow({ width: 800, height: 600 })
  win.loadURL(`file://${__dirname}/index.html`)
  win.webContents.on('did-finish-load', () => {
    win.webContents.send('ping', 'whoooooooh!')
  })
})

If I remove the loading of an external script file ...

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <title>Hi mom</title>
  <!-- <script defer src="renderer.js"></script> -->
</head>
<body>
  <div id="renderer"></div>
</body>
</html>

... then the order of events is changed slightly ...

dom-ready
did-finish-load
ready-to-show

... which may explain why some of the other answers to this question contract each other.

ChrisW
  • 54,973
  • 13
  • 116
  • 224
-1

These days, you use the "ready-to-show" event.

https://electronjs.org/docs/api/browser-window#using-ready-to-show-event

user240515
  • 3,056
  • 1
  • 27
  • 34