For other translations of this series, see JS working mechanism – Xiaobai 1991 column – Nuggets (juejin. Cn)

The scenarios WebWorker uses are limited and may be rarely used if not computationally intensive tasks.

This time take a look at Webworkers: We’ll take an overview of the different types of workers, how they work together, and their strengths and weaknesses in different scenarios. Finally, five scenarios for picking the right Woker are provided. As we know, JS is single-threaded, but it can be programmed asynchronously.

Limitations of asynchronous programming

Scheduling delayed code in EventLoop. Asynchronous programming in this way makes your UI more responsive by allowing UI rendering to take precedence

A common type of asynchronous programming is AJAX requests. Because requests take a lot of time, with asynchrony, you can execute other code while waiting for a response

// This is assuming that you're using jQuery
jQuery.ajax({
    url: 'https://api.example.com/endpoint',
    success: function(response) {
        // Code to be executed when a response arrives.
    }
});
Copy the code

But this is still a problem, because AJAX requests are handled by the browser’s WEB API, and what if you want the rest of your code to execute asynchronously? For example, what if the successful callback of the request is a very CPU intensive code? Computer tasks generally fall into two categories, one is IO intensive and the other is CPU intensive.

var result = performCPUIntensiveCalculation();
Copy the code

If performCPUIntensiveCalculation not an HTTP request, but a obstructive code (for example a large for loop), so no way to release the EventLoop or defrosted browser UI – all user behavior will not be responded to. As you can see, asynchronous functions solve only a small part of the problem caused by single threading. Sometimes, you can use setTimeout. To perform long computations and make the UI less sluggish. Split some complex operations into separate setTimeouts so that they can be executed at different points in the EnenvtLoop to buy time for UI rendering and response. Consider a simple example that calculates the average of all the numbers in an array:

function average(numbers) {
    var len = numbers.length,
        sum = 0,
        i;

    if (len === 0) {
        return 0;
    } 
    
    for (i = 0; i < len; i++) {
        sum += numbers[i];
    }
   
    return sum / len;
}
Copy the code

If it is asynchronous, it can look like this:

function averageAsync(numbers, callback) {
    var len = numbers.length,
        sum = 0;

    if (len === 0) {
        return 0;
    } 

    function calculateSumAsync(i) {
        if (i < len) {
            // Put the next function call on the event loop.
            setTimeout(function() {
                sum += numbers[i];
                calculateSumAsync(i + 1);
            }, 0);
        } else {
            // The end of the array is reached so we're invoking the callback.
            callback(sum / len);
        }
    }

    calculateSumAsync(0);
}
Copy the code

Use the setTimeout method to add each step of the operation to the EventLoop. In between each calculation, there is plenty of time to do other calculations and unfreeze the browser.

Web Workers takes care of this

The H5 brings us a lot of surprises, such as:

  • SSE (discussed in the previous chapter)
  • The geographical position
  • Application in channeling
  • The local store
  • Drag and drop
  • Web Workers

A Web Worker is a thread built into the browser that you can use to execute JS code.

The whole JS paradigm is based on a single-threaded environment, and WebWorker can solve this problem. Web Workers allow developers to put time-consuming and computationally intensive tasks into the background without clogging the UI. You don’t need to use setTimeout to do this. Take a look at this simple demo to understand the difference between sorting arrays with and without WebWorker.

Web Worker overview

Web Workers allow you to process long-running scripts without blocking the UI—- they are executed in parallel. Web Workers are truly multithreaded. But isn’t JS single threaded?

You should be aware that JS does not actually define a threading model. Web Workers are not part of JS; they are browser features that can be invoked through JS. Most browsers have historically been single-threaded, and most JS implementations happen in the browser. WebWorkers are not implemented in Node –Node has a slightly different concept of “cluster” or “child_process”. Notice that there are three types of Web workers declared in the specification:

  • Dedicated Workers
  • Shared Workers
  • Service workers

Dedicated Workers

The Dedicated Web Worker is instantiated by the main thread and the value can communicate with it. Browsers support the following:

Shared Workers

Shared workers can be accessed by the same thread (including different tabs, iframes, or other Shared workers). Browsers support the following:

Service Workers

The Service Worker is an event-driven Worker that consists of a source and a path. It controls its associated web pages, interprets and modifies navigation, requests for resources, and a very fine-grained way of caching resources that gives you great flexibility to control your program’s behavior in certain situations (such as when the network is unavailable). Browsers support the following:

In this article, we will focus on Dedicated Workers and call them “Web Workers” or “Workers”.

How do Web Workers work

The Implementation of Web Workers, like a.js file, contains asynchronous HTTP requests in the page. These requests are completely hidden from the developer.

Workers use thread-like information passing to achieve parallelism. They are perfectly suited to keep the UI up to date and responsive.

Web Workers run in a thread separate from the browser. Therefore, the code they execute needs to be placed in a separate file. This is important. Take a look at how a basic Woker is created:

var worker = new Worker('task.js');
Copy the code

If the “task.js” file is accessible, the browser will start a new thread for the asynchronous download. Once the download is complete, Woker will be launched to execute it.

If the file path returns 404, the worker fails silently (without throwing an exception). To start creating a woker, you need to call the postMessage method:

worker.postMessage();
Copy the code

Web Worker communication

To communicate between the Worker and the page that created it, you need to use the postMessage method or a Broadcast Channel.

PostMessage method

Newer browsers support JSON objects as the first argument to this method. Older browsers only support string. For a simple example, see how a page can create a woker and communicate back and forth with it by passing a JSON object.

<button onclick="startComputation()">Start computation</button>

<script>
  function startComputation() {
    worker.postMessage({'cmd': 'average', 'data': [1, 2, 3, 4]});
  }

  var worker = new Worker('doWork.js');

  worker.addEventListener('message', function(e) {
    console.log(e.data);
  }, false);
  
</script>
Copy the code

Part of the worker code looks like this:

self.addEventListener('message', function(e) {
  var data = e.data;
  switch (data.cmd) {
    case 'average':
      var result = calculateAverage(data); // Some function that calculates the average from the numeric array.
      self.postMessage(result);
      break;
    default:
      self.postMessage('Unknown command');
  }
}, false);
Copy the code

When a Button is clicked, the main page calls postMessage. The worker.postmessage line passes the JSON object to woker and adds the CMD and data values and keys respectively. The worker will process information through a defined message handle

When the message arrives, the worker actually performs the calculation without blocking the Event loop. The worker checks the passed event E and executes it as a standard JS function. When all is finished, the result of the function is returned to the main page.

In the context of Worker, self and this both refer to the Worker’s global.

There are two ways to stop a worker: the home page calls worker.terminate() or the worker itself calls self.close().

Broadcast Channel

Broadcast channels are more commonly used apis for communication. It allows us to broadcast information to all contexts of the same origin. All browser tabs,iframes or workers of the same origin can send and receive messages

// Connection to a broadcast channel
var bc = new BroadcastChannel('test_channel');

// Example of sending of a simple message
bc.postMessage('This is a test message.');

// Example of a simple event handler that only
// logs the message to the console
bc.onmessage = function (e) { 
  console.log(e.data); 
}

// Disconnect the channel
bc.close()
Copy the code

From the picture below, you can see more clearly what Broadcast Channels look like

However, browser support for Broadcast channels is not very good:

The size of the message delivered

There are two ways to pass information to Web Workers:

  • Copy message: The message is serialized, copied, sent, and then deserialized at the other end. Pages and workers do not share the same instance, so a copy is created each time it is passed. Most browsers do this by automatically encoding/decoding JSON message values on either end. As expected, these operations on data significantly increase the performance overhead of messaging. The larger the message, the longer the transmission time.
  • Message delivery: the source sender cannot be used again after the message is sent, and the data is delivered immediately. The only limitation is the ArrayBuffer

Available features of Web workers

Web Workers can only access part of the functionality of JS because of its multithreaded nature. Here’s a list of features:

  •  navigatorobject
  •  locationObject (read only)
  • XMLHttpRequest
  • setTimeout()/clearTimeout() and setInterval()/clearInterval()
  • The application cache
  • useimportScripts()Import external scripts
  • Create other Workers

Web Worker limited

It’s a shame WebWoker doesn’t have access to some of the more critical JS features

  • DOM (Thread Unsafe)
  •  windowobject
  •  documentobject
  •  parentobject

Thus, the Worker cannot manipulate the DOM. Once you learn to use workers properly, you’ll start using them like a calculator, while other code can perform UI operations. Workers process all the recomputation and then pass the result to the page where it was created for updates on the page

Exception handling

As with any JavaScript code, You’ll want to handle any errors that are thrown in your Web Workers. If an error occurs while a worker is executing you, the ErrorEvent is fired. The interface contains three useful properties for figuring out what went wrong: Just like any JS code, you can handle all exceptions in your Worker. If an exception occurs while the worker is executing, ErrorEvent will be fired. This interface contains three useful attributes to indicate exception information:

  • Filename – The name of the script in which the error occurred
  • Lineno – The location where the error occurred
  • Message – Description of the error message

Here’s an example:

function onError(e) {
  console.log('Line: ' + e.lineno);
  console.log('In: ' + e.filename);
  console.log('Message: ' + e.message);
}

var worker = new Worker('workerWithError.js');
worker.addEventListener('error', onError, false);
worker.postMessage(); // Start worker without a message.
Copy the code
self.addEventListener('message', function(e) {
  postMessage(x * 2); // Intentional error. 'x' is not defined.
};
Copy the code

Here we create a worker and start listening for error events

Inside the worker (in workerWitheror.js) we create an internal exception — add X by 2, but X is undefined. This exception is passed to the script that initializes it, and onError is raised.

A great scenario for using Web Workers

We’ve already discussed Worker’s strengths and weaknesses to see which scenarios work for it

  • ** Raytracing **: Raytracing is a rendering technique that generates an image using traced raypaths as textures. Raytracing is a very CPU intensive calculation that requires simulating effects such as reflection, refraction, materials, and so on. All of this calculation logic needs to be added to the Worker to avoid blocking the UI thread. Even better, you can slice and dice images between several workers at will (using multiple cpus). Here’s a simple example

– nerget.com/rayjs-mt/ra… .

  • Encryption: End-to-end encryption is becoming more popular as personal and sensitive information becomes more demanding. Encryption can be time consuming, especially if there is a large amount of data to encrypt (for example, encrypt data before sending it to the server). This is a great scenario for using workers because it doesn’t require access to the DOM. Once entering worker, it is insensitive to users and does not affect user experience.

  • Preloading data: To optimize your code and improve load events, you can use the worker to preload and store data so you can use it when you need it. In this scenario, Worker’s performance is very good.

  • Progressive Web applications: These applications load quickly even if the network is unstable. This means that the data needs to be stored locally in the browser. This is where IndexDB and some similar apis are needed. This is all required for client storage. In order not to block the UI, these things need to be executed in the Worker. When using IndexDB, it is possible to use its asynchronous interface instead of workers, but previously it also had a synchronous interface (which may be reintroduced) and IndexDB must be used in Workers.

  • Spell check:

A common spell checker works like this – the program reads dictionary files with the correct spelling. The dictionary is converted to a search tree to make text searches more efficient, and when Cheker provides a word, the program checks to see if it’s in the tree. If not, the user is provided with an alternate spelling by providing an alternate character and checking if it is what the user wants to write. This process can easily be transferred to the Worker so that when the user enters any word or sentence, the UI does not block and all search and spelling suggestions are performed.