Does the electron framework allow multi-threading through web workers?
I am having a hard time googling how I would do multi-threading if I made an electron app. Would it be with web workers?
In the renderer process you can create Web Workers, and those will run in their own threads, however Node integration will be disabled in those Web Workers because Node isn’t thread-safe. So if you want to run something in a separate thread that uses Node then you’ll need to spawn a separate process, you can do so with child_process.fork()
and then communicate with the new process using send()
.
On Electron, Node.js and Processes
Electron works on the same principles as Node. In Node.js, threads are not the atomic unit of execution. You work within the event loop and execution is async by default. See here for details. That being said, you can spin up multiple child processes in Node.js by forking them.
Here is an example.
//forking a process using cluster
var cluster = require('cluster');
var http = require('http');
var numCPUs = 4;
if (cluster.isMaster) {
for (var i = 0; i < numCPUs; i++) {
cluster.fork();
}
} else {
http.createServer(function(req, res) {
res.writeHead(200);
res.end('process ' + process.pid + ' says hello!');
}).listen(8000);
}
Credits to How to create a Node.js cluster for speeding up your apps for the example.
Electron Specific Concepts
Coming back to Electron, there are a couple additional concepts to be aware of. Processes in Electron are unique in that they come in 2 flavors.
Render Process – A process that contains a web page. These processes are created in a sandbox as are typical web pages.
Main Process – The process that bootstraps your application. It creates render processes and their web pages. It also can act as the communication hub for all spawned render processes via rpc.
Here is the main.js portion of the sample from the Electron Tutorial. This is the main process calling a browser window. Take particular note of the mainWindow
variable.
'use strict';
const electron = require('electron');
const app = electron.app; // Module to control application life.
const BrowserWindow = electron.BrowserWindow; // Module to create native browser window.
// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
var mainWindow = null;
// Quit when all windows are closed.
app.on('window-all-closed', function() {
// On OS X it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
if (process.platform != 'darwin') {
app.quit();
}
});
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
app.on('ready', function() {
// Create the browser window.
mainWindow = new BrowserWindow({width: 800, height: 600});
// and load the index.html of the app.
mainWindow.loadURL('file://' + __dirname + '/index.html');
// Open the DevTools.
mainWindow.webContents.openDevTools();
// Emitted when the window is closed.
mainWindow.on('closed', function() {
// Dereference the window object, usually you would store windows
// in an array if your app supports multi windows, this is the time
// when you should delete the corresponding element.
mainWindow = null;
});
});
TL;DR:
Threads do not exist in Node.js and Electron is a framework built on Node.js\io.js and Chromium. Electron’s foundation is Node.js. You can spawn child processes with forking in Node.js.
According to the Multithreading docs:
With Web Workers, it is possible to run JavaScript in OS-level threads.
All built-in modules of Node are supported, however none of Electron’s built-in modules or modules with native bindings should be used in Web Workers as they are not designed to be thread-safe.
Check out Electron Edge. It enables you to run .NET code and node.js in a single process (no IPC needed, better performance). This means you can leverage .NET’s multi-threading model with the single-threadedness of node.js.
It will run on Linux, Mac and Windows, thanks to .NET Core.