JS is a single-threaded environment by nature, which means you cannot run multiple scripts at the same time. Why is that? Because the design goal of JS is to realize the interaction between the web page and the user, imagine that when the user clicks on the page and manipulates the DOM, two threads simultaneously manipulate the DOM, so whose result will be the standard? The worst-case scenario is that one thread needs to add content to an element and another thread removes it, leaving users unable to interact with the page. This is why JS can only be single-threaded, all tasks are executed on one thread and there is no need to worry about multi-threading. Where JS needs to execute two tasks at the same time, asynchronous technologies such as timers and event handlers can be used to achieve parallelism (in fact, it is still single threaded). HTML5 introduces Web workers to achieve true multithreading. The Web Worker performs operations in the background, such as triggering long-running scripts to handle computationally intensive tasks, without blocking UI or other scripts from handling user interactions. Workers implement parallelism using thread-like messaging. This is perfect for ensuring UI refresh, performance, and responsiveness to users.
Type of Web worker
Two types:
- Dedicated workers (Dedicated workers) : can only be used in the script that creates it;
- Shared workers: Can be used in multiple scripts.
The communication between worker and main thread is carried out through the message mechanism — the postMessage function is used to pass data to the other party, and the other party obtains and processes data by listening to message events. Data is not shared, it is replicated. So when you pass an object, you can manipulate that object without affecting an object in another thread.
The script of worker and main thread must be homologous, which simply means that the same website is loaded into browsing.
A dedicated worker
Worker feature detection
Check whether the browser supports worker in the main thread, and then decide whether to create worker.
if(window.worker){
//do something
}
Copy the code
It is currently supported by all major browsers. For more details
Introduction to use
The Web worker runs in a separate thread, saving its code in a separate JS file and then importing the script when the worker is created. Many browsers do not support local file running worker, we need to combine with server time. You can use Express to create a server.
Create worker.js in the public/javascripts folder:
this.addEventListener('message', (event) => {
console.log(this)
console.log(event)
console.log(event.data)
console.log(event.origin)
console.log(event.ports)
console.log(event.source)
console.log(event.lastEventId)
self.postMessage({ name: 'worker.js'.data: 'hello,main.js! '})},false)
Copy the code
This is the code for the worker thread.
Create the worker in the JS code of the page. For simplicity, write the script in the script tag:
<script>
let worker = new Worker('/javascripts/worker.js');// Create a worker
let workerButton = document.getElementByI('workerButton');
workerButton.addEventListener('click', (event)=> {
console.log(event)
worker.postMessage({ name: 'main.js'.data:'hello,worker.js! ' });// Send a message to the worker thread
}, false)
// Listen for messages sent by worker threads
worker.addEventListener('message', (event) => {
console.log(event.data);
}, false)
</script>
Copy the code
The script specified when creating the worker is loaded asynchronously, and if loaded successfully, a worker thread is generated. The system cannot generate workers properly before full loading and execution. If the script does not exist, 404 is returned, creating the worker failed.
PostMessage is used to start the worker and also to send messages.
Stop the worker
In the main thread, stop the worker via worker.terminate(); In the worker thread, use close() to stop the worker.
let stopWorker = document.getElementById('stopWorker');
stopWorker.addEventListener('click', () = > {let result = worker.terminate();
console.log(result);
}, false);
Copy the code
The worker stops by herself:
Tell the worker to stop in the main thread:
let stopWorker = document.getElementById('stopWorker');
stopWorker.addEventListener('click', () = > {let result = worker.postMessage('stop');
console.log(result);//undefined
}, false)
Copy the code
worker.js
this.addEventListener('message', (event) => {
console.log(this)
console.log(event)
console.log(event.data)
console.log(event.origin)
console.log('cache'.this.cache)
console.log(event.source)
console.log(event.lastEventId)
if ('stop' === event.data) {
let result = this.close();
console.log('worker stop ',result);//undefined
}
self.postMessage({ name: 'worker.js'.data: 'hello,main.js! '})},false)
Copy the code
The worker environment
Worker scope: In worker script files, this and self are both global scopes. The output of console.log(this) above is:
DedicatedWorkerGlobalScope.Copy the code
The main thread cannot be used in worker threads, only some JS functions can be used:
- The navigator object;
- The location object;
- The XMLHttpRequest object.
- The timer.
- Application cache;
- importScripts();
- Generate other workers.
Cannot be used in worker:
- DOM(non-thread-safe);
- The window object;
- The document object;
- The parent object.
We send an HTTP request to worker.js, get the return value, and pass it to the main thread:
Copy the code
More details
Load external worker script
You can use the importScripts function to load external scripts into the worker script for execution.
Record a script in worker.js:
importScripts('./importTest.js');// Multiple paths can be passed, and paths are relative to worker.js
Copy the code
importTest.js
test(5)
function test(time) {
setInterval((a)= > {
console.log('hello');
}, 1000 * time);
Copy the code
When the worker thread stops, the loaded external script stops executing.
Error handling
Can handle worker thread errors in the main thread, listen for worker error events in the main thread:
worker.addEventListener('error', (event) => {
console.log(event.colno);
console.log(event.filename);
console.log(event.message);
}, false);
Copy the code
Output the error event, you can see some properties of the event: no bubbling, cancelable, etc., with some properties of ordinary events.
The worker generates an error:
this.addEventListener('message', (event) => {
if ('stop' === event.data) {
let result = this.close();
console.log('worker stop ', result);
}
self.postMessage({ name: 'worker.js'.data: 'hello,main.js! ' })
this.postMessage(new Error('Make a mistake! '));
}, false)
Copy the code
Embedded worker
In the example above, put the worker code in a separate file. This makes it easier to manage the code and modify it. Because of syntax highlighting, you can put the worker code in an HTML file related to the main thread:
<script id="worker" type="javascript/worker">
this.addEventListener('message', (event) => {
if ('stop' === event.data) {
this.close();
}
console.log(event.data);
self.postMessage({ name: 'worker.js'.data: 'hello,main.js! ' });
}, false);
</script>
<script>
let workerContent = document.getElementById('worker').textContent;
let blob = new Blob([workerContent], { type: 'text/javacript' });
let url = URL.createObjectURL(blob);
console.log(url);
let worker = new Worker(url);
worker.addEventListener('message', (event) => {
console.log(event.data);
});
let workerButton = document.querySelector('#workerButton');
workerButton.addEventListener('click', (event) => {
worker.postMessage({ name: "Main thread" });
}, false);
</script>
Copy the code
If the worker’s code is put in script tag and the type is javascript/worker, it will not be parsed into JS code by the browser. Instead, it will be regarded as ordinary HTML tag, and the text inside the tag can be obtained through DOM API to create worker. Create a worker using a Blob to generate a Blob object using url.createObjecturl.
let blob = new Blob([workerContent], { type: 'text/javacript' });
let url = URL.createObjectURL(blob);
console.log(url);
let worker = new Worker(url);
Copy the code
About BLOBs About BloBs and urls
The usage scenario of worker
Common scenarios:
- Prefetching and/or caching data for later use;
- Highlight code syntax or other real-time text formatting;
- Spell checker;
- Analyze video or audio data;
- Background I/O or network service polling;
- Handle large arrays or oversized JSON responses;
- Image filtering in
- Update multi-line content in a local network database.
More reference
Basic information about Web Workers
Use Web Workers
Worker reads file