问题
I want to run a simple function asynchronously in Electron, so it doesn't block my render thread. So, something (very roughly) like this (within render.js
):
var max = 42; // Somehow needs to be passed to the function
function foo() {
for (var i = 0; i < max; i++) {
// Do something...
// ... and tell the render thread about it.
}
}
foo(); // Should run asynchronously
There are two requirements:
- I must pass parameters to the function (here:
max
). These could not only be integers, but also objects. The function must not run before it recieves these parameters. - While running, there must be a communication channel to the render thread. For example, to periodically report progress from within the
for
loop all the way to the UI, or to abort the function when an event in the render thread fires.
Here is a more specific minimal working (or rather, not working) example. The purpose is to send serial commands to a physical apparatus, on which a probe should be moved to all locations in a specified grid. So I need two loops (one for x, one for y). The loop body will contain functions that block until the motors have moved, than a mesurement from that location must be communicated back to the UI. Also, before the loops start running, the specifications about the grid must be known (hence my requirement about passing parameters.)
var Parameters = {x_length: 50, y_length: 50};
//These functions interact with a serial device and block until it is done with its task
function moveTo(x, y) {/*...*/};
function measure() {/*...*/};
//This function should eventually be executed asynchronously
function scan() {
for (var x = 0; x < Parameters.x_length; x++) {
for (var y = 0; y < Parameters.y_length; y++) {
moveTo(x, y);
var result = measure();
// Here, we need to tell the render thread about results. I used
// postMessage (WebWorker syntax) as a placeholder.
postMessage({
position: {x: x, y: y},
data: result
});
}
}
}
// This is what will be actually called, e. g. when the user clicks a
// button.
function scan_async() {
//Again, I used WebWorker (or rather, TinyWorker) syntax as a placeholder.
var scan_worker = new Worker(scan);
scan_worker.onmessage = function (msg) {
console.log(msg.data);
};
}
After hours of very frustrating googeling, I found a lot of approaches, but non of them seems like the "definitive" way to do it, or doesn't meet the above points, or seems way to complicated for what I want to achieve.
What I found so far:
- Actually using WebWorkers (or rather something TinyWorkers, https://github.com/avoidwork/tiny-worker), like in the code above. Here, there seems to be no elegant way to pass the starting parameters before the worker starts running.
- Create a new, hidden
BrowserWindow
, as mentioned here. However, I can't find anything about this method elsewhere.
So, is there a "correct", more straight-forward way to achieve my goal?
回答1:
Actually using WebWorkers (or rather something TinyWorkers)
Yes. This is how you move code to a different thread.
Here, there seems to be no elegant way to pass the starting parameters before the worker starts running.
- Create the worker. Don't have it do anything except listen for
postMessage
events. - Send a message to it, with
postMessage
with the starting parameters - An event listener in the worker gets the message and starts running the job
- When it is done,
postMessage
from the work to the main application - An event listener in the main application gets the message with the results
来源:https://stackoverflow.com/questions/51795352/whats-the-correct-way-to-run-a-function-asynchronously-in-electron