JavaScript Async - Advanced Worker Threads
Written by Ian Elliot   
Monday, 16 July 2018
Article Index
JavaScript Async - Advanced Worker Threads
Running a worker without a separate file
Shared and Service Workers

 

In the Worker thread we can use the ArrayBuffer in the standard way:

this.addEventListener("message",
   function(event){
      console.log("Worker got data! " +      
                    event.data.byteLength);
   });

And you will see the message:

Worker got data! 8

indicating that the ArrayBuffer is now available in the Worker thread.

The Worker can pass the ArrayBuffer back to the UI thread:

this.addEventListener("message",
     function(event){
       console.log("Worker got data! " +     
                       event.data.byteLength);
       postMessage(event.data,[event.data]);
       console.log("Worker sent data! " +
                      event.data.byteLength);
});

After the data has been transferred back to the UI thread you once again will see that the length of the ArrayBuffer is zero.

In the UI thread the data can be retrieved in the usual way:

worker.addEventListener("message",
      function (event) {
         console.log("UI after return " +
                        event.data.byteLength);
         console.log("UI after return original " +
                        arrayBuf.byteLength);
});

In this case you will see that the event.data is an ArrayBuffer of eight bytes and the original arrayBuf is still zero – that is the original transferred data is not restored.

You can, of course, restore the reference to the original data:

worker.addEventListener("message",
     function (event) {
        console.log("UI after return " + 
                       event.data.byteLength);
        arrayBuf=event.data;
           console.log("UI after return original "
                       + arrayBuf.byteLength);
});

Now it looks as if the original data has been handed back by the Worker thread.

The big problem with transferring data is that the thread that owned it originally doesn't get the use of it, not even a copy, while the other thread is using it. This doesn't matter as long as the initial owner is generating the data for the first time. For example, if a Worker thread is downloading a resource it can transfer it to the UI thread to be used with no problems. Compare this to a Worker thread that is modifying rather than originating the data. If the UI thread passes the Worker thread a bitmap to process, what does the UI thread show while the worker has ownership?

At the time of writing support for ImageBitmap is restricted to Firefox and Chrome and is best avoided.

coverasync

 

Shared and Service Workers

There are other types of Worker object that you can use, but these are more specialized and not as well supported. In particular, Safari dropped support to both Shared and Service workers.

A SharedWorker is another thread that can be accessed from multiple browsing contexts – windows, iframes or other workers. You create a shared worker using:

var worker=new SharedWorker(url);

Communication is via postMessage as per a standard Worker thread, but now we have to use a port object to make the connection. You have to start the port and then you use its postMessage method:

worker.port.start();
worker.port.sendMessage(data);

The connection from the SharedWorker back to the UI thread is performed via the onconnect event:

this.addEventListener("onconnect",
   function(event){
     var port=e.ports[0];
      ...

Once you have the port object you can send messages using it:

port.start();
port.sendMessage(data);

Apart from the need to use a port object to send messages, the only other difference is that a single instance of the Worker code serves all of the other threads making use of it. To take advantage of a Shared Worker's abilities you really need to store the port object as different threads connect to it. By keeping a list of ports, the SharedWorker can pass data from one thread to another and hence one window or iFrame to another. Notice that the one origin rule applies to SharedWorkers and all code and windows have to have come from the same source domain.

SharedWorkers are interesting, but until Apple decides to support them they are probably not a good gamble. ServiceWorkers on the other hand might be. They provide facilities that make the offline experience of using a web app much more like that of a native app. As such some see the ServiceWorker as the future of the web. At first Apple withdrew support for ServiceWorkers in Safari, but it is currently under consideration. The final chapter is devoted to using ServiceWorkers.

Summary 

  • You can create a Worker object which runs on a different thread to the UI thread.

  • The UI thread doesn't share any objects with the new thread and vice versa.

  • The Worker thread has access to all of JavaScript and a subset of the global objects available to the UI thread.

  • Communication from the thread that created the Worker object to the new thread makes use of its postMessage method.

  • Communication from the Worker thread to the thread that created it also makes use of the postMesssage method, but of the DedicatedWorkerGlobalScope object.

  • In each case a message event is triggered on the appropriate thread and the data property of the event object provides the data sent as part of the message.

  • The data transferred to the worker thread and to the UI thread is a copy, a clone, of the original.

  • By limiting the way the thread can interact, the JavaScript programmer is protected from the main difficulties of multi-threading and we don't have to worry about locks and race conditions.

  • A big problem with using Worker threads is that communication is event driven, but the Worker thread is at its most simple when just ignoring asynchronous considerations and just gets on with the job.

  • To allow for responsive communication between the threads both have to be written in an asynchronous style. Any long running function in the Worker thread will mean that it doesn't respond to messages sent to it from the UI thread.

  • You can use a Blob object and a Data URL to avoid having to use a separate file for the Worker's code.

  • A faster way to exchange data between threads is to use transferable objects.

  • As well as dedicated Workers you can also create SharedWorkers which can pass messages between different threads and ServiceWorkers which make implementing web apps easier. Neither are supported by Safari.

 

Now Available as a Book:

 JavaScript Async

cover

You can buy it from: Amazon

Contents

  1. Modern JavaScript (Book Only)
  2. Events,Standard & Custom
  3. The Callback
      extract - The Callback & The Controller
  4. Custom Async - setTimeout, sendMessage & yield
      extract - Custom Async
      extract - Avoiding State With Yield 
  5. Worker Threads
      extract - Basic Worker ***NEW
      extract - Advanced Worker Threads 
  6. Consuming Promises 
  7. Producing Promises
      extract - The Revealing Constructor Pattern
     
    extract - Returning Promises
     
    extract - Composing Promises
  8. The Dispatch Queue
      extract - Microtasks
  9. Async & Await
      extract -  Basic Async & Await
      extract -  DoEvents & Microtasks
  10. Fetch, Cache & Service Worker
      extract - Fetch  
      extract - Cache
     
    extract -  Service Workers

Also by Ian Elliot 
Just JavaScript: An Idiomatic Approach
Just jQuery: The Core UI 
Just jQuery: Events, Async & AJAX  

To be informed about new articles on I Programmer, sign up for our weekly newsletter, subscribe to the RSS feed and follow us on Twitter, Facebook or Linkedin.

espbook

 

Comments




or email your comment to: comments@i-programmer.info

<ASIN:1871962560>

<ASIN:1871962579>

 <ASIN:1871962528>

<ASIN:1871962501>



Last Updated ( Monday, 16 July 2018 )