In the browser, 'normal' JavaScript code is run in a single thread (a thread is a light-weight CPU process, see this Wikipedia page for details). This means that the browser GUI, the JavaScript, and other tasks are competing for processor time. If you run an intensive CPU task, everything else is blocked, including the user interface. You have no doubt observed something like this during your Web browsing experiences:
With Internet Explorer:
Or maybe:
A solution for this problem, offered by HTML5, is to run certain CPU-intensive tasks in separate threads from the one managing the graphical user interface. So, if you don't want to block the user interface, you can perform computationally intensive tasks in one or more background threads, using the HTML5 Web Workers. Web Workers = CPU threads, in JavaScript.
Terminology check: if the terms background and foreground and the concept of multi-tasking are new to you, please review PC Mag's definition of foreground and background.
This example will block the user interface unless you close the tab. Try it at JSBin but DO NOT CLICK ON THE BUTTON unless you are prepared to kill your browser/tab, because this routine will consume 100% of CPU time, completely blocking the user interface:
Code from the example:
<!DOCTYPE HTML>
<html>
<head>
<title>Worker example: One-core computation</title>
</head>
<body>
<button id="startButton">Click to start discovering prime numbers</button><p> Note that this will make the page unresponsive, you will have to close the tab in order to get back your CPU!
<p>The highest prime number discovered so far is: <output id="result"></output></p>
<script>
function computePrime() {
var n = 1;
search: while (true) {
n += 1;
for (var i = 2; i <= Math.sqrt(n); i += 1)
if (n % i == 0)
continue search;
// found a prime!
document.getElementById('result').textContent = n;
}
}
document.querySelector("#startButton").addEventListener('click', computePrime);
</script>
</body>
</html>
Notice the infinite loop in the function computePrime (line 12, in bold). This is guaranteed to block the user interface. If you are brave enough to click on the button that calls the computePrime() function, you will notice that the line 18 execution (that should normally modify the DOM of the page and display the prime number that has been found) does nothing visible. The UI is unresponsive. This is really, really, bad JavaScript programming - and should be avoided at all costs.
Shortly we will see a "good version" of this example that uses Web Workers.
When programming with multiple threads, a common problem is "thread safety". This is related to the fact that several concurrent tasks may share the same resources (e.g. JavaScript variables) at the same time. If one task is modifying the value of a variable while another one is reading it, this may result in some strange behavior. Imagine that thread number 1 is changing the first bytes of a 4 byte variable, and thread number 2 is reading it at the same time: the read value will be wrong (1st byte that has been modified + 3 bytes not yet modified).
With Web Workers, the carefully controlled communication points with other threads mean that it's actually very hard to cause concurrency problems. There's no access in a worker to non-thread safe components or to the DOM. We must pass specific data into and out of a thread through serialized objects. The separate threads share different copies so the problem with the four bytes variable, explained in the previous paragraph, cannot occur.
There are two different kinds of Web Workers described in the specification:
Dedicated Web Workers: threads that are dedicated to one single page/tab. Imagine a page with a given URL that runs a Web Worker that counts in the background 1-2-3- etc. It will be duplicated if you open the same URL in two different tabs. So each independent thread will start counting from 1 at startup time (when the tab/page is loaded).
Shared Web Workers: these are threads which may be shared between different pages of tabs (they must conform to the same-origin policy) on the same client/browser. These threads will be able to communicate, exchange messages, etc. For example, a shared worker that counts in the background 1-2-3- etc. and communicates its current value. All the pages/tabs which share its communication channel will display the same value! Also, if you refresh each of those pages, they will return displaying the same value as each other. The pages don't need to be the same (with the same URL). However, they must conform to the "same origin" policy.
Shared Web Workers are not studied in this course. They are not yet supported by major browser vendors, and a proper study would require a whole module's worth of material. We may cover this topic in a future version of this course when implementations are more stable/available.
Web Workers concepts and usage (from MDN's documentation)
Using Web Workers (from MDN's documentation)
Browser support: