Abstract: Understand Web Workers.
- How does JavaScript work: Building blocks of Web Workers + 5 scenarios for using them
- Author: Front-end xiaozhi
FundebugReproduced with authorization, copyright belongs to the original author.
This is the seventh article in a series devoted to exploring JavaScript and the components it builds.
If you missed the previous chapters, they can be found here:
- How JavaScript works: An overview of the engine, runtime, and call stack!
- How JavaScript works: Dive into the V8 Engine & 5 Tips for Writing Optimized Code!
- How JavaScript works: Memory Management + How to Handle 4 common Memory Leaks!
- How JavaScript works: Event loops and the rise of asynchronous programming + 5 ways to code better with async/await!
- How JavaScript works: Explore websocket and HTTP/2 with SSE + how to choose the right path!
- How JavaScript works: Compare to WebAssembly and its usage scenarios!
This time we will walk through Web Workers step by step, starting with a simple concept and then discussing the different types of Web Workers, how their components work together, and their respective strengths and limitations in different scenarios. Finally, five scenarios for proper use of Web Workers are provided.
As we discussed in previous articles, you should be aware that the JavaScript language uses a single-threaded model. However, JavaScript also offers developers the opportunity to write asynchronous code.
Limitations of asynchronous programming
Previous articles have discussed asynchronous programming and when you should use it.
Asynchronous programming allows the UI to be responsive (rendering fast), allowing the UI to render first through “code scheduling”, which allows code requiring request time to be placed in the Event loop and executed later.
A good use case for asynchronous programming is AJAX requests. Because requests can take a lot of time, asynchronous requests can be used and other code can be executed while the client waits for the response.
However, this presents a problem — requests are handled by the browser’s WEB API, but how do you make the rest of your code asynchronous? For example, if the code in the successful callback is cpu-intensive:
var result = performCPUIntensiveCalculation();
Copy the code
If performCPUIntensiveCalculation instead of an HTTP request a block of code (such as a for loop content many loops), there was no way to clear the event loop in time, the browser UI rendering will be blocked, the page can not timely response to the user.
This means that asynchronous functions can only address a small part of the limitations of the JavaScript language’s single threading.
In some cases, you can use setTimeout to block long-running computations, and you can use setTimeout to temporarily queue asynchronously to render pages faster. For example, by batching complex computations in separate setTimeout calls, they can be placed in separate “locations” in the event loop, which can fight for execution time for UI rendering/response.
Look at a simple function that calculates the average of an array of numbers:
Here’s how to override the above code and “simulate” asynchrony:
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 function, which adds each step of the calculation further into the event loop. In between each calculation, there will be enough time for other calculations to allow the browser to render.
Web workers can solve this problem
HTML5 brings us a lot of new things, including:
- SSE(which we described and compared with WebSockets in a previous article)
- Geolocation
- Application cache
- Local Storage
- Drag and Drop
- Web Workers
Description of Web Worker
The function of Web Worker is to create a multithreaded environment for JavaScript, allowing the main thread to create Worker threads and assign some tasks to the latter to run. While the main thread is running, the Worker thread is running in the background without interfering with each other. Wait until the Worker thread completes the calculation and returns the result to the main thread. The advantage of this is that when computationally intensive or high-latency tasks are taken on by Worker threads, the main thread (usually responsible for UI interactions) will flow smoothly and will not be blocked or slowed down.
You may ask, “Isn’t JavaScript a single-threaded language?”
JavaScript is actually a language that doesn’t define a threading model. Web Workers are not part of JavaScript, but rather a browser feature that can be accessed through JavaScript. Historically, most browsers were single-threaded (of course, this has changed), and most JavaScript implementations took place in the browser. Web Workers are not implemented in Node.js. Node.js has similar concepts of cluster and child_process, which are also multi-threaded but different from Web Workers.
It is worth noting that there are three types of Web Workers mentioned in the specification:
- Dedicated Workers
- Shared Workers
- Service Workers
Dedicated Workers
Dedicated Workers can only be accessed by the page that created it, and can only communicate with it. Here’s what the browser supports:
Shared Workers
Shared Workers can be accessed by various processes under the same origin, including: Iframes, different TAB pages in the browser (a TAB page is a separate process, so Shared Workers can be used to communicate between TAB pages), and other Shared Workers. Here’s what the browser supports:
Service workers
Service Worker functions:
- Background messaging
- Network proxy, forwarding requests, forging responses
- Offline caching
- Being pushed
At the present stage, the main capabilities of Service workers focus on network proxy and offline cache. In terms of concrete implementation, it can be understood that a Service Worker is a Web Worker that can still run when the Web page is closed. Here’s what the browser supports:
This paper mainly discusses dedicated Workers. Without special declaration, Web Workers and Workers are referred to as dedicated Workers.
How do Web Workers work
Web Workers are typically built with scripts for.js files, with asynchronous HTTP requests in the pages, which are completely hidden and you only need to call the Web Worker API.
Worker leverages message passing between class threads to achieve parallelism. They ensure real-time, high-performance, and responsive presentation of the interface to the user.
Web Workers run in a separate thread in the browser. Therefore, the code they execute needs to be contained in a separate file. This is very important to remember!
Let’s look at how basic Workers are created:
var worker = new Worker('task.js');
Copy the code
The argument to the Worker() constructor is a script file that is the task to be performed by the Worker thread. Since the Worker cannot read local files, the script must come from the network. If the download does not succeed (such as a 404 error), the Worker silently fails.
To start the created Worker, call the postMessage method:
worker.postMessage();
Copy the code
Web Worker communication
To communicate between the Web Worker and the page that created it, you need to use the postMessage method or Broadcast Channel.
PostMessage method
Newer browsers support JSON objects as the first argument to methods, whereas older browsers only support strings.
Take a look at an example of how the page that created the Worker communicates with the JSON object by passing it as a more “complex” example. You pass strings the same way you pass objects.
Let’s take a look at the following HTML page (or, more accurately, part of it):
<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
Then here is the JS code in worker:
self.addEventListener('message'.function(e) {
var data = e.data;
switch (data.cmd) {
case 'average':
var result = calculateAverage(data); // A function that computes the average value from an array of values
self.postMessage(result);
break;
default:
self.postMessage('Unknown command'); }},false);
Copy the code
When the button is clicked, postMessage is invoked from the home page. The postMessage line passes the JSON object to the Worker. The Worker listens and processes the message through a defined message handler.
When the message arrives, the actual calculation is performed in the worker without blocking the event loop. The Worker checks the event parameter e passed, executes it like a JavaScript function, and returns the result back to the home page.
In the Worker scope, both this and self refer to the Worker’s global scope.
There are two ways to stop workers: call worker.terminate() from the home page or call self.close() inside the Worker.
Broadcast Channel
The Broadcast Channel API allows all Windows,iFrames, and so on under the same raw domain and user agent to interact. That is, if a user opens two tabs on the same site, both tabs will be notified of updates if the site content changes.
Still don’t understand? Take Facebook as an example. If you have one window open on Facebook, but you haven’t logged in yet, and then you open another window to log in, you can notify other Windows/tabs that a user has logged in and request them to update the page accordingly.
// 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
A Broadcast Channel can be seen visually in the following diagram:
Broadcast Channel browser support is limited:
Message size
There are two ways to send messages to Web Workers:
- Replicated messages: Messages are serialized, copied, sent, and then deserialized at the other end. Page and Worker do not share the same instance, so the final result is that a copy will be created for each transmission. Most browsers use JSON to encode and decode values on both sides, so the data decoding and encoding operation is bound to increase the time cost of message transmission. The bigger the message, the longer it takes to send.
- Pass the message: This means that the original sender cannot use it once it has been sent. The limitation of transferring data almost instantaneously is that it can only be passed using the ArrayBuffer type.
Features available for Web Workers
Due to the multithreaded nature of JavaScript, Web workers have access to only a subset of JavaScript features. Here are some of its features:
Web Workers have access to only a subset of JavaScript features due to their multithreaded nature. The following is a list of available features:
- The navigator object
- Location object (read only)
- MLHttpRequest
- setTimeout()/clearTimeout() and setInterval()/clearInterval()
- Application Cache
- use
importScripts()
Importing external scripts - Create additional Web Workers
Limitations of Web Workers
Unfortunately, Web Workers do not have access to some very critical JavaScript features:
- DOM(which makes threading unsafe)
- The window object
- The document object
- The parent object
This means that Web workers cannot manipulate the DOM (and therefore the UI). This can be tricky at times, but once you understand how to use Web Workers properly, you’ll start using them as separate “computers,” and all UI changes will happen in your page code. Workers will do all the grunt work for you and return the results to the Page once completed.
Handling errors
Just like JavaScript code, you need to handle errors thrown by Web Workers. When the Worker encounters an error during execution, an ErrorEvent event will be triggered. The interface contains three useful attributes to help troubleshoot problems:
- Filename – The name of the script causing the Worker
- Lineno – The line number where the error occurred
- Message – Description of an error
Examples are as follows:
From here, you can see that we created a worker and started listening for error events.
Inside the worker (in workerWitheror.js), we create an exception by multiplying undefined x by 2. Exceptions are propagated to the initial script, which then listens for error events through the page to catch errors.
Five good Web Workers application instances
So far, we’ve listed the benefits and limitations of Web Workers. Now let’s look at what their most powerful use cases are:
- Ray tracing is a rendering technique that generates images by tracing the path of light in pixels. Raytracing uses CPU intensive math to simulate the path of light. The idea is to simulate effects such as reflection, refraction, materials, etc. All of this calculation logic can be added to the Web Worker to avoid blocking the UI thread. Even better — it’s easy to split image rendering between multiple workers (and between multiple cpus). Here is a simple demonstration of ray tracing using Web Workers – nerget.com/rayjs-mt/r…. .
- End-to-end Encryption is growing in popularity due to increased regulation of personal and sensitive data. Encryption can be very time consuming, especially if there is a lot of data that needs to be encrypted frequently (for example, before it is sent to the server). This is a great scenario to use a Web Worker because it doesn’t require access to the DOM or anything fancy — it’s a pure algorithm that does its job. As long as it works in the Web Worker, it is seamless for the end user and does not affect the experience.
- ** To optimize your website or Web application and improve data load time, you can utilize Web Workers to load and store data ahead of time so that you can use it later if you need to fetching data. Web Workers are great in this case because they don’t affect the UI of the application, unlike when Workers are not used.
- **Progressive Web Apps: ** These Progressive Web applications require quick loading even when the user’s network is unstable. This means that the data must be stored locally in the browser. This is where IndexDB, or a similar API, comes in. In general, client-side storage is necessary, but it needs to be used without blocking the UI rendering thread, so the work needs to be done in the Worker. However, IndexDB, for example, provides asynchronous apis that do not require the Use of a Web worker to call, but that must be used in the worker if the API is synchronous.
- ** A basic Spell checker works as follows – the program reads a dictionary file with a list of correctly spelled words. The dictionary is parsed into a search tree to make the actual text search more efficient. When a word is provided to the inspector, the program checks to see if it exists in the pre-built search tree. If the word is not found in the tree, you can provide the user with an alternative spelling by replacing the replacement character and testing if it is a valid word (if it is a word the user wants to write). All these processes can be carried out in the Web Worker. Users can input words and sentences without being blocked, and the Web Worker verifies whether the words are correct and provides alternative words in the background.
The original:
blog.sessionstack.com…
The bugs that may exist after code deployment cannot be known in real time. In order to solve these bugs, I spent a lot of time on log debugging. Incidentally, I recommend a good BUG monitoring tool for youFundebug.
Your likes are my motivation to keep sharing good things.
A stupid code farmers, my world can only lifelong learning!
More content please pay attention to the public account “big move the world”!
About Fundebug
Fundebug focuses on real-time BUG monitoring for JavaScript, wechat applets, wechat games, Alipay applets, React Native, Node.js and Java online applications. Since its launch on November 11, 2016, Fundebug has handled more than 900 million error events, and paid customers include Google, 360, Kingsoft, Minming.com and many other brands. Welcome to try it for free!