Usage and cases of Web Woeker and Shared Worker

Article directory

  • 1 Introduction
  • 2. Introduction to Web Worker
  • 3. Instructions for use and compatibility
    • 3.1. Instructions for use
    • 3.2. Compatibility
  • 4. Use Web Worker
    • 4.1. Create Web Worker
    • 4.2. Communicate with the main thread
    • 4.3. Terminate Web Worker
    • 4.4. Monitor error messages
  • 5. Use Shared Worker
    • 4.5. Debugging Shared Worker
  • 6. Some pitfalls in use
    • 6.1. Other files introduced in Web Woeker
    • 6.2. Use in WebPack or Vite
      • 6.2.1, used in webpack
      • 5.2.2, used in vite
    • 5.3. Problems with the introduction of sharedWorker
  • 7. Postscript

1. Foreword

The interface stuck in a project I was working on recently. After some investigation, I found out that it was because some data had been formatted and generated. Originally there were only 1,000 pieces of data, but after processing, it became N million pieces of data (business demand), causing the page to render very slowly or even crash. So I thought about optimizing it. It is not loaded during initialization. When needed, the Web Worker is used to process the data to avoid the main thread getting stuck.

2. Introduction to Web Worker

Before introducing it, let’s talk about why Web Worker was born.

Because the JavaScript language uses a single-threaded model, that is to say, all tasks can only be completed on one thread, and only one thing can be done at a time. The previous tasks have not been completed, and the subsequent tasks can only wait. With the enhancement of computer computing power, especially the emergence of multi-core CPUs, single-threading has brought great inconvenience and cannot fully utilize the computer’s computing power.

The role of Web Worker is to create a multi-threaded environment for JavaScript. It is part of the HTML5 standard and gives developers the ability to operate multiple threads using JavaScript. Allow the main thread to create Worker threads and assign some tasks to the Worker threads to run. While the main thread is running, the Worker thread is running in the background, and the two do not interfere with each other. Wait until the Worker thread completes the calculation task, and then returns the result to the main thread. The advantage of this is that some computing-intensive or high-latency tasks are burdened by the Worker thread, and the main thread (usually responsible for UI interaction) will be smooth and will not be blocked or slowed down.

3. Instructions for use and compatibility

Before using Worker, you need to understand some rules and browser compatibility to avoid some problems.

3.1. Instructions for use

  1. Resource consumption: Once the Worker thread is successfully created, it will always run and will not be interrupted by activities on the main thread (such as the user clicking a button or submitting a form). This is conducive to responding to the main thread’s communication at any time. However, it also causes the Worker to consume more resources, so it is recommended to close it after use.

  2. Same-origin restriction: The script file assigned to the Worker thread must have the same origin as the script file of the main thread.

  3. DOM limitation: The global object where the Worker thread is located is self, which is different from the main thread. It cannot read the window, DOM, document, parent and other global objects of the webpage where the main thread is located, but it can read the navigator and location objects of the main thread. .

  4. Script limitation: XMLHttpRequest and Axios can be used in Web Workers to send requests.

  5. Communication: The Worker thread and the main thread are not in the same context, they cannot communicate directly and must be completed through messages.

  6. File restrictions: Local files cannot be read in the Worker thread, that is, the local file system (file://) cannot be opened. The script it loads must come from the network.

3.2, Compatibility

td>

Browser Compatibility Minimum compatible version
Chrome Fully compatible 4.0 (2008)
Firefox Fully compatible 3.5 (2009)
Safari Fully compatible with 3.1 (2007)
Edge Fully compatible 79 (2020)
IE Partially compatible 10 (2012)
Opera Fully compatible 10.5 (2010)

4. Use Web Worker

Directly use JavaScript’s native Worker() constructor, whose parameters are as follows:

Parameters Description
path The address of a valid js script must comply with the same origin policy
options.type Optional. Used to specify the worker type. The value can be classic or module. The default is classic
options.credentials optional. Specify worker credentials. The value can be omit, same-origin, or include. If not specified, or type is classic, the default omit will be used (no credentials required)
options.name Optional. In the case of DedicatedWorkerGlobalScope, a DOMString value representing the scope of the worker, primarily for debugging purposes.

4.1. Create Web Worker

Main thread:

const myWorker = new Worker('/worker.js')

//Receive message
myWorker.addEventListener('message', (e) => {<!-- -->
console.log(e.data)
})

//Send message to worker thread
myWorker.postMessage('Greeting from Main.js')

4.2. Communication with the main thread

worker thread:

//Receive message
self.addEventListener('message', (e) => {<!-- -->
console.log(e.data)
})

// After a calculation, send the message
const calculateDataFn = () => {<!-- -->
self.postMessage('ok')
}

4.3. Terminate Web Worker

You can operate in both threads, you can choose freely.

  • Operate in the main thread:
//Create worker
const myWorker = new Worker('/worker.js')
// Close the worker
myWorker.terminate()
  • Operate in the worker thread:
self.close()

4.4. Monitoring error messages

Web Worker provides two event listening error callbacks, error and messageerror.

Event Description
error Triggered when an error occurs within the worker
messageerror Triggered when the message event receives parameters that cannot be deserialized
  • Operate in the main thread:
//Create worker
const myWorker = new Worker('/worker.js')

myWorker.addEventListener('error', (err) => {<!-- -->
console.log(err.message)
})

myWorker.addEventListener('messageerror', (err) => {<!-- -->
console.log(err.message)
})
  • In the worker thread:
self.addEventListener('error', (err) => {<!-- -->
console.log(err.message)
})
self.addEventListener('messageerror', (err) => {<!-- -->
console.log(err.message)
})

5. Use Shared Worker

SharedWorker allows multiple pages to share the same background thread, allowing for more efficient resource utilization and collaborative computing. The following is an example, page1 and page2 share a background thread:

  • sharedWorker.js
/**
 * @description The collection of all connections to this worker
 */
const portsList = []

/**
 * @description Connection success callback
 */
self.onconnect = (event) => {<!-- -->
//The port currently triggering the connection
const port = event.ports[0]
// add in
portsList.push(port)
//Callback when message is received
port.onmessage = (event) => {<!-- -->
// Get the delivered message
const {<!-- --> message, value } = event.data
\t\t// calculate
let result = 0
switch (message) {<!-- -->
case 'add':
result = value * 2
break
case 'multiply':
result = value * value
break
default:
result = value
}
//Send message to all connected targets
portsList.forEach((port) => port.postMessage(`${<!-- -->message}The result is: ${<!-- -->result}`))
}
}
  • sharedWorkerHook.js
const sharedWorker = new SharedWorker(new URL('../../utils/webworker.js', import.meta.url), 'test')

export default sharedWorker
  • page1
<template>
  <div @click="sendMessage">Click 1</div>
</template>

<script>
import sharedWorkerHook from './sharedWorkerHook'

export default {<!-- -->
  name: '',
  data() {<!-- -->
    return {<!-- -->}
  },
  computed: {<!-- -->},
  created() {<!-- -->},
  mounted() {<!-- -->
    sharedWorkerHook.port.start()
    //Receive the results returned by SharedWorker
    sharedWorkerHook.port.onmessage = event => {<!-- -->
      console.log(event.data)
    }
  },
  methods: {<!-- -->
    sendMessage() {<!-- -->
      sharedWorkerHook.port.postMessage({<!-- --> message: 'add', value: 1 })
    }
  }
}
</script>
  • page2
<template>
  <div @click="sendMessage">Click 2</div>
</template>

<script>
import sharedWorkerHook from './sharedWorkerHook'

export default {<!-- -->
  name: '',
  data() {<!-- -->
    return {<!-- -->}
  },
  computed: {<!-- -->},
  created() {<!-- -->},
  mounted() {<!-- -->
    sharedWorkerHook.port.start()
    //Receive the results returned by SharedWorker
    sharedWorkerHook.port.onmessage = event => {<!-- -->
      console.log(event.data)
    }
  },
  methods: {<!-- -->
    sendMessage() {<!-- -->
      sharedWorkerHook.port.postMessage({<!-- --> message: 'multiply', value: 1 })
    }
  }
}
</script>

4.5, Debugging Shared Worker

When debugging in sharedWorker, use console to print information. It will not appear in the console of the main thread. You need to enter chrome://inspect/ in the Chrome browser address bar and enter the debugging panel to see it. The steps are as follows:

  1. Enter chrome://inspect in the Chrome browser address bar and press Enter to enter
  2. In the left menu bar, click sharedWorker
  3. In the menu bar on the right, click inspect to open the debugging panel.

Debug Shared Worker

6. Some pitfalls in use

During use, although I checked some documents and blogs, the following problems still occurred. Please record them.

6.1, Other files introduced in Web Woeker

In some scenarios, the tasks that need to be processed by the worker process are very complex, and other files will be introduced. At this time, we can use the importScripts() method in the worker thread to load the js files we need.

importScripts('./utils.js')

If the ESModule mode is introduced, the type mode needs to be specified during initialization.

const worker = new Worker('/worker.js', {<!-- --> type: 'module' })

6.2. Use in WebPack or Vite

To use it in webpack and vite, the steps are as follows:

6.2.1, used in webpack

Step 1: Install the plug-in: worker-plugin

npm install worker-plugin -D

Step 2: Configure in configureWebpack.plugins of vue.config.js

const WorkerPlugin = require('worker-plugin')

module.exports = {<!-- -->
  outputDir: 'dist',
  //The rest of the configuration...
  configureWebpack: {<!-- -->
    devServer: {<!-- -->
      open: false,
      host: 'localhost',
      //The rest of the configuration...
    },
    plugins: [
      //The rest of the configuration...
      new WorkerPlugin()
    ]
  }
}

Step 3: Use

const webWorker = new Worker(new URL('../utils/worker.js', import.meta.url), {<!-- -->
  type: 'module'
})

5.2.2, used in vite

Step 1: Install the plug-in: worker-plugin

npm install worker-plugin -D

Step 2: Configure in plugins of vite.config.js

import worker from 'worker-plugin'

const viteConfig = defineConfig((mode: ConfigEnv) => {<!-- -->
return {<!-- -->
plugins: [vue(), worker()],
server: {<!-- -->
host: '0.0.0.0',
port: 7001,
open: true
}
}
})

export default viteConfig

Step 3: Use

const webWorker = new Worker(new URL('../utils/worker.ts', import.meta.url), {<!-- -->
  type: 'module'
})

5.3. Problems with the introduction of sharedWorker

In the process of using sharedWorker, I found that there is always only one instance in the sharedWorker process, but I did initialize the same sharedWorker js file on several pages. Finally, debugging found that the reason was that the name changed after being introduced through the plug-in. One is xxxx0.js and one is xxxx1.js, so every time I initialize, they are not considered to be the same instance, so the messages cannot be synchronized.

  • Solution: Just like the example in [Use Shared Worker] (#5-Use Shared Worker), use a new file to create this sharedWorker, then export it, and then execute it after importing the required page.

like

7. Postscript

In this article, we learned the role and use of Web Worker, and how to use Web Worker in Vue. Finally, we also learned how to use Shared Worker.

In fact, there is a more powerful member of the webworker family, which is Service Worker. It can do many things, such as intercepting global fetch events, caching static resources/offline caching for first-screen loading, background synchronization, message push, etc. However, the space is limited, so I will explain it next time.

That’s it for this sharing. I am Peng Duoduo. If you find it helpful, please comment, follow, like, and forward. See you next time~

Previous articles

  • PC-side online music website built by Vue2 Family Bucket + Element
  • vue3 + element-plus configure cdn
  • Vue3 tutorial to help you get started with Vue3 Family Bucket
  • VueX4 tutorial to help you get started with Vue3 Family Bucket
  • Vue-Router4 tutorial to help you get started with Vue3 Family Bucket
  • Super detailed! Nine communication methods in Vue
  • Super detailed! Vuex step-by-step tutorial
  • Use nvm to manage node.js version and replace npm Taobao mirror source
  • In vue, .env files are used to store global environment variables and configure vue startup and packaging commands.
  • Super detailed! Vue-Router step-by-step tutorial

Personal homepage

  • CSDN
  • GitHub
  • Simple book
  • Blog Garden
  • nuggets