Search code examples
electronnwjs

NWJS, Electron - DOM not updating during long-running process


Just as in this unanswered question, I have a long-running process, during which I wish to update an the HTML of the app's only window -- but the DOM does not get updated until after the above process has completed.

This is the case with both NW and Electron.

The code is getting called, because the same routine also logs to the console - which is access through a window instance passed to the process, which is in a Node module.

I can find no documentation that references such issues, and no Chromium flag which might help.

When using setInterval to populate the innerText of an element with the time every second, the updates stop during the long-running file-parsing process.

Edit: this question is my first result on a Google search for 'NWJS not updating DOM'....


Solution

  • Long-running processes that block the Chromium main process will also block the renderer.

    The solution is to create a separate process, and have it send status updates back to renderer via IPC:

            this._service = fork(
                path.join(__dirname, 'service'),
                [],
                { stdio: ['inherit', 'inherit', 'inherit', 'ipc'] }
            );
    
            this._service.on('error', (err) => {
                console.log('child error', err);
            });
    
            this._service.on('message', msg => {
                console.log('message from child:', msg);
                switch (msg.cmd) {
                    case 'hello':
                        console.log('hello from parent');
                        break;
                    case 'log':
                        this.parentLog(msg.html);
                        break;
                    case 'progress':
                        this.progressBar.update(msg.pc);
                        break;
                }
            });
    

    In the spawned subprocess (named service.js in the above example), use process.send to transmit JSON to the parent:

    const childLog = (html) => {
        process.send({ cmd: 'log', html: html });
    }
    

    Note that if your parent is not the Electron renderer, it could be accessing the DOM via a window passed from the renderer.