5

Right now, I've got this, and it works:

var myWebWorker = new Worker('myWebWorker.js');
myWebWorker.onmessage = function (myEvent) {
    $('#Print').append('Return value: ' + myEvent.data + "<br>");
};
myWebWorker.postMessage(2);

My question is: Can I do this instead?

var result = myWebWorker.postMessage(2);

Because I need the web worker to be synchronous - in other words, give a return value and also don't return until you're finished.

Edit 1:

The web worker is doing an insert/select onto a local database using openDatabaseSync transactions.

Edit 2:

It appears that my problem is with Cocoa Touch and not with JavaScript. Here's a clever hack that someone has posted on StackOverflow.

Edit 3:

Here's a better hack.

Community
  • 1
  • 1
Phillip Senn
  • 46,771
  • 90
  • 257
  • 373
  • **WHY** does it need to be synchronous? Are you getting data from the `onmessage` callback? – Shmiddty Mar 20 '13 at 19:30
  • Yes, I'm getting data correctly from the onmessage callback. But the person writing the Cocoa Touch part of this application doesn't know how to listen for it. Maybe there's something that Cocoa touch can listen for that I can fire off using JavaScript, like a click event or something. – Phillip Senn Mar 20 '13 at 20:11

2 Answers2

7

The point of web workers is to delegate tasks without blocking the UI. They can't be synchronous.

You probably don't need the task to be synchronous but you need to design your code around events and asynchronous tasks just like you can't design any javascript application nor any serious GUI application with only synchronous operations.

Denys Séguret
  • 372,613
  • 87
  • 782
  • 758
  • I have a device that's issuing a JavaScript command and is expecting a result back. I don't think that it knows about any callbacks - it just issues a command and expects a result, so everything I do must be synchronous. – Phillip Senn Mar 20 '13 at 19:14
  • What's your device ? It's very strange for a software to expect a synchronous result from a javascript command. If your task must be synchronous (which is very probably the wrong requirement), why are you trying to use a webworker ? – Denys Séguret Mar 20 '13 at 19:15
  • An iPad. I don't think Cocoa Touch can listen for events - can it? – Phillip Senn Mar 20 '13 at 19:17
  • 2
    Well, I'm no expert in iOS but calling JavaScript from a Cocoa application to update a local database and then expect JavaScript to synchronously use a web worker for that looks like a strange design. There probably is a simpler solution to your problem. – Denys Séguret Mar 20 '13 at 19:27
4

As already said, you can't call the worker synchronously. You could write a wrapper that waits for the worker to return a message, but that has the same effect as executing the worker's code directly in you caller's code. The caller would be blocked for the time the worker code runs.

When you should use workers:

CPU1  CPU2    Explanation
 A            # Main script starts (in one Thread/CPU)
 |            # still runs...
 |---->B      # Offload some heavy work to Worker B (to another Thread/CPU)
 |     |      # A can do other stuff while B does some heavy work that would block A
 |<----B      # B is ready and posts the result to A
 |            # A is interrupted only shortly by B's message
 V

I hope this makes things clearer.

I am hesitating to add this code (i.e., please rethink your need for calling a Worker synchronously), but even writing a sync wrapper does not work (Thx to the commenters):

function syncMe(){
    var w = new Worker('myWebWorker.js');
    var data = null, ready = false;
    w.onmessage = function (e) {
        ready = true;
        data = e.data;
    };         
    w.postMessage(2)
    while(!ready){ /* block this thread forever, since `ready` is never changed */ }
    console.log(data);
}

Edit: "Why You can't sync a worker like this"

The onmessage handler will never be called because the JavaScript VM can only call one function a time and the syncMe function has not yet exited. (Sorry for the confusion)

Juve
  • 10,584
  • 14
  • 63
  • 90
  • `while(!ready){ /* block this thread! */ }` ? I think you shouldn't suggest this. – Denys Séguret Mar 20 '13 at 19:30
  • @dystroy I know, I think I also make clear that I should not. But it shows nicely how the main thread is blocked. People need examples to learn. – Juve Mar 20 '13 at 19:33
  • 2
    This won't work. the `onmessage` callback will wait until the code finishes... which it won't. – John Dvorak Mar 20 '13 at 19:33
  • 1
    Yeah, I think that it won't work. I've tried that before experimenting with web workers and I think the while(!ready) loop keeps onmessage from ever being called. – Phillip Senn Mar 20 '13 at 19:35
  • 2
    Maybe my question has more to do with Cocoa Touch development than it does JavaScript. – Phillip Senn Mar 20 '13 at 19:36
  • well... it does wait. There's no way to wait for an event synchronously (except maybe with `alert`) – John Dvorak Mar 20 '13 at 19:36
  • OK I get the point. I never used synchronous Webworkers before, of course ;). It just looked like the most obvious way to force-sync a worker. – Juve Mar 20 '13 at 19:39
  • Of course... the main function first has to exit before the main thread can call another function. The JS VM can execute only one function at a time. The onmessage handler can never be triggered. Damn, I guess it is too late in the evening to answer SO questions. – Juve Mar 20 '13 at 19:45