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