Hacker News new | ask | show | jobs
by derefr 1861 days ago
But the main NodeJS process can spawn (regular POSIX) worker threads, just like any other GUI app’s main (event loop) process; and those worker threads can both 1. load native libraries and call into them, and 2. communicate just as directly with the renderer as the main thread can. The renderer, meanwhile, only gives you ServiceWorkers; and those can’t do anything natively. (Plus, they have all the same IPC overhead to the main renderer context that calling the renderer from Node does.)

Think of it like this: let’s say you’re creating an Electron equivalent to Mathematica. You have a big native blob of maths evaluation code. Where are you going to run it — in the renderer (as Emscripten WASM) or in a worker thread of the native app (as a native static library or DLL)?

Or let’s say you’re doing an Electron BitTorrent client. Where are you going to handle the network connections and do the file management and... basically everything the app does? Well, in this case, you have no real option: the renderer can’t open raw TCP sockets. You’ve got to do it native. (But it would have been the better choice anyway, for IOPS reasons—localStorage + virtualized attachment downloads don’t buy you very much disk concurrency.)

A less clear-cut case is a game engine. The answer there depends on whether you can get a handle to the renderer’s Canvas from your native code. If so, then the choice is obvious: native game engine, draw to renderer’s canvas. If not, it might still be more CPU efficient to go native: you might be able to approximate that over RPC if your game has a bandwidth-efficient wire protocol representation of its render command stream (as e.g. most 2D tile based games do.) Only if neither of these work would putting the game engine into the renderer be optimal.