Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Javascript dedicated web worker to send messages on demand

Is it possible to write a simple dedicated web worker so it process something continuously and sends its state only when the client asks.

What I've done so far, the Client file :

<script>
    // spawn a worker
    var worker = new Worker('basic-worker.js');
    // decide what to do when the worker sends us a message
    worker.onmessage = function(e){
        document.getElementById('result').textContent = e.data;
    };
</script>
<html>
<head></head>
<body>
    <p>The Highest prime number discovered so far : <outpout id="result"></output></p>
</body>
</html>

The worker file :

var n = 0;
search: while (true) {
    n += 1;
    for (var i = 2; i <= Math.sqrt(n); i += 1)
        if (n % i == 0)
        continue search;
    // found a prime !
    postMessage(n);
}

As you can see the worker send continuously the primes it founds. I would like to be able to launch the prime calculation and asks the worker to send the latest prime he founds when I click a button on the client for example. That would be something like (I know it cannot work as but to give a general idea of what i want) :

Worker file :

var n = 0;
var lPrime = 0;
// post last prime number when receiving a message
onmessage = function(e) {
    postMessage(lPrime);
}
// continously search for prime numbers
search: while (true) {
    n += 1;
    for (var i = 2; i <= Math.sqrt(n); i += 1)
        if (n % i == 0)
        continue search;
    // found a prime !
    //postMessage(n);
    lPrime = n;
}

Client file :

<script>
    // spawn a worker 
    var worker = new Worker('basic-worker.js');
    // what to do when the worker sends us a message
    worker.onmessage = function(e){
        document.getElementById('result').textContent = e.data;
    };
    // post to the worker so the worker sends us the latest prime found
    function askPrime(){
        worker.postMessage();
    };
</script>
<html>
<head></head>
<body>
    <p>The Highest prime number discovered so far : <outpout id="result"></output></p>
    <input type="button" onclick="askPrime();">
</body>
</html>
like image 363
Arno 2501 Avatar asked Jun 17 '13 10:06

Arno 2501


1 Answers

This is not a good pattern. Workers are single-threaded, so at any given moment, they can either:

  1. perform a calculation,

  2. send an event, or

  3. respond to an event.

While your worker is calculating, it cannot respond to events. When you send a request for the latest prime, you must wait for the worker to finish what it is doing before it can process your request. Of course, you can use setTimeout (or other methods) to allow the browser to "interrupt" the current work (see Javascript - how to avoid blocking the browser while doing heavy work?), but the entire point of workers is to save you from resorting to such needless complexity.

A better pattern would be a non-worker variable that holds the latest prime, and is updated by the worker whenever it find a new prime. You can query that variable whenever you need the latest prime, and you never need to wait for the worker to process your request.

// spawn a worker 
var worker = new Worker('basic-worker.js');

// store the latest prime as it is produced
var latestPrime = 1;
worker.onmessage = function(e){
    latestPrime = e.data;
};

// fetch the latest prime from the variable
function askPrime(){
    document.getElementById('result').textContent = latestPrime;
};

You could also accomplish this pattern by having two workers:

  1. The main script spawns a worker that holds the latest known prime.

  2. That worker spawns a second worker that actually does the work and reports new primes to the first worker as they are discovered.

That way, the first worker doesn't do any work, and is always free to respond with the latest prime, and the second worker never needs to stop its computations to respond to requests.

like image 200
apsillers Avatar answered Nov 02 '22 07:11

apsillers