前端 Web Workers 简介

2023-12-11 00:36

本文主要是介绍前端 Web Workers 简介,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

简介

以前我们总说,JS 是单线程没有多线程,当 JS 在页面中运行长耗时同步任务的时候就会导致页面假死影响用户体验,从而需要设置把任务放在任务队列中;执行任务队列中的任务也并非多线程进行的,然而现在 HTML5 提供了我们前端开发这样的能力 - Web Workers API,我们一起来看一看 Web Worker 是什么,怎么去使用它,在实际生产中如何去用它来进行产出。

概述

Web Workers 使得一个 Web 应用程序可以在与主执行线程分离的后台线程中运行一个脚本操作。这样做的好处是可以在一个单独的线程中执行费时的处理任务,从而允许主(通常是 UI)线程运行而不被阻塞。

它的作用就是给 JS 创造多线程运行环境,允许主线程创建 worker 线程,分配任务给后者,主线程运行的同时 worker 线程也在运行,相互不干扰,在 worker 线程运行结束后把结果返回给主线程。这样做的好处是主线程可以把计算密集型或高延迟的任务交给 worker 线程执行,这样主线程就会变得轻松,不会被阻塞或拖慢。这并不意味着 JS 语言本身支持了多线程能力,而是浏览器作为宿主环境提供了 JS 一个多线程运行的环境。

不过因为 worker 一旦新建,就会一直运行,不会被主线程的活动打断,这样有利于随时响应主线程的通性,但是也会造成资源的浪费,所以不应过度使用,用完注意关闭。或者说:如果 worker 无实例引用,该 worker 空闲后立即会被关闭;如果 worker 实列引用不为 0,该 worker 空闲也不会被关闭。

兼容性

在这里插入图片描述

注意事项

worker 线程的使用有一些注意点:

  1. 同源限制 worker 线程执行的脚本文件必须和主线程的脚本文件同源,这是当然的了,总不能允许 worker 线程到别人电脑上到处读文件吧
  2. 文件限制 为了安全,worker 线程无法读取本地文件,它所加载的脚本必须来自网络,且需要与主线程的脚本同源
  3. DOM 操作限制 worker 线程在与主线程的 window 不同的另一个全局上下文中运行,其中无法读取主线程所在网页的 DOM 对象,也不能获取 document、window等对象,但是可以获取navigator、location(只读)、XMLHttpRequest、setTimeout族等浏览器API
  4. 通信限制 worker 线程与主线程不在同一个上下文,不能直接通信,需要通过postMessage方法来通信
    脚本限制 worker 线程不能执行alert、confirm,但可以使用 XMLHttpRequest 对象发出 ajax 请求

示例

在主线程中生成 Worker 线程很容易:

var myWorker = new Worker(jsUrl, options)

Worker() 构造函数,第一个参数是脚本的网址(必须遵守同源政策),该参数是必需的,且只能加载 JS 脚本,否则报错。第二个参数是配置对象,该对象可选。它的一个作用就是指定 Worker 的名称,用来区分多个 Worker 线程。

// 主线程var myWorker = new Worker('worker.js', { name : 'myWorker' });// Worker 线程
self.name // myWorker

关于 api 什么的,直接上例子大概就能明白了,首先是 worker 线程的 js 文件:

workerThread1.js 文件中

关于 api 什么的,直接上例子大概就能明白了,首先是 worker 线程的 js 文件:// workerThread1.jslet i = 1function simpleCount() {i++self.postMessage(i)setTimeout(simpleCount, 1000)
}simpleCount()self.onmessage = ev => {postMessage(ev.data + ' 呵呵~')
}

在 HTML 文件中的 body 中:

HTML 文件中的 body 中:<!--主线程,HTML文件的body标签中--><div>Worker 输出内容:<span id='app'></span><input type='text' title='' id='msg'><button onclick='sendMessage()'>发送</button><button onclick='stopWorker()'>stop!</button>
</div><script type='text/javascript'>if (typeof(Worker) === 'undefined')	// 使用Worker前检查一下浏览器是否支持document.writeln(' Sorry! No Web Worker support.. ')else {window.w = new Worker('workerThread1.js')window.w.onmessage = ev => {document.getElementById('app').innerHTML = ev.data}window.w.onerror = err => {w.terminate()console.log(error.filename, error.lineno, error.message) // 发生错误的文件名、行号、错误内容}function sendMessage() {const msg = document.getElementById('msg')window.w.postMessage(msg.value)}function stopWorker() {window.w.terminate()}}
</script>

api

主线程中的api,worker表示是 Worker 的实例:

  • worker.postMessage: 主线程往 worker 线程发消息,消息可以是任意类型数据,包括二进制数据
  • worker.terminate: 主线程关闭 worker 线程
  • worker.onmessage: 指定 worker 线程发消息时的回调,也可以通过worker.addEventListener(‘message’,cb)的方式
  • worker.onerror: 指定 worker 线程发生错误时的回调,也可以 worker.addEventListener(‘error’,cb)

Worker 线程中全局对象为 self,代表子线程自身,这时 this指向self,其上有一些 api:

  • self.postMessage: worker 线程往主线程发消息,消息可以是任意类型数据,包括二进制数据
  • self.close: worker 线程关闭自己
  • self.onmessage: 指定主线程发 worker 线程消息时的回调,也可以self.addEventListener(‘message’,cb)
  • self.onerror: 指定 worker 线程发生错误时的回调,也可以 self.addEventListener(‘error’,cb)

注意,w.postMessage(aMessage, transferList) 方法接受两个参数,aMessage 是可以传递任何类型数据的,包括对象,这种通信是拷贝关系,即是传值而不是传址,Worker 对通信内容的修改,不会影响到主线程。事实上,浏览器内部的运行机制是,先将通信内容串行化,然后把串行化后的字符串发给 Worker,后者再将它还原。一个可选的 Transferable 对象的数组,用于传递所有权。如果一个对象的所有权被转移,在发送它的上下文中将变为不可用(中止),并且只有在它被发送到的 worker 中可用。可转移对象是如 ArrayBuffer,MessagePort 或 ImageBitmap 的实例对象,transferList数组中不可传入 null。

worker 线程中加载脚本的 api:

importScripts('script1.js')	// 加载单个脚本
importScripts('script1.js', 'script2.js')	// 加载多个脚本

使用场景

个人觉得,Web Worker 我们可以当做计算器来用,需要用的时候掏出来摁一摁,不用的时候一定要收起来。

加密数据 有些加解密的算法比较复杂,或者在加解密很多数据的时候,这会非常耗费计算资源,导致 UI 线程无响应,因此这是使用 Web Worker 的好时机,使用 Worker 线程可以让用户更加无缝的操作 UI。

预取数据 有时候为了提升数据加载速度,可以提前使用 Worker 线程获取数据,因为 Worker 线程是可以是用 XMLHttpRequest 的。

预渲染 在某些渲染场景下,比如渲染复杂的 canvas 的时候需要计算的效果比如反射、折射、光影、材料等,这些计算的逻辑可以使用 Worker 线程来执行,也可以使用多个 Worker 线。

复杂数据处理场景 某些检索、排序、过滤、分析会非常耗费时间,这时可以使用 Web Worker 来进行,不占用主线程。

预加载图片 有时候一个页面有很多图片,或者有几个很大的图片的时候,如果业务限制不考虑懒加载,也可以使用 Web Worker 来加载图片,可以参考一下这篇文章的探索这篇文章的探索,这里简单提要一下。

// 主线程
let w = new Worker("js/workers.js");
w.onmessage = function (event) {var img = document.createElement("img");img.src = window.URL.createObjectURL(event.data);document.querySelector('#result').appendChild(img)
}// worker线程
let arr = [...好多图片路径];
for (let i = 0, len = arr.length; i < len; i++) {let req = new XMLHttpRequest();req.open('GET', arr[i], true);req.responseType = "blob";req.setRequestHeader("client_type", "DESKTOP_WEB");req.onreadystatechange = () => {if (req.readyState == 4) {postMessage(req.response);}}req.send(null);
}

在实战的时候注意

  1. 虽然使用 worker 线程不会占用主线程,但是启动 worker 会比较耗费资源
  2. 主线程中使用 XMLHttpRequest 在请求过程中浏览器另开了一个异步 http 请求线程,但是交互过程中还是要消耗主线程资源

在 Webpack 项目里面使用 Web Worker 请参照:怎么在 ES6+Webpack 下使用 Web Worker

参考文章

mdn

前端 Web Workers 到底是什么

Web Worker在项目中的妙用

这篇关于前端 Web Workers 简介的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/478846

相关文章

前端原生js实现拖拽排课效果实例

《前端原生js实现拖拽排课效果实例》:本文主要介绍如何实现一个简单的课程表拖拽功能,通过HTML、CSS和JavaScript的配合,我们实现了课程项的拖拽、放置和显示功能,文中通过实例代码介绍的... 目录1. 效果展示2. 效果分析2.1 关键点2.2 实现方法3. 代码实现3.1 html部分3.2

解决JavaWeb-file.isDirectory()遇到的坑问题

《解决JavaWeb-file.isDirectory()遇到的坑问题》JavaWeb开发中,使用`file.isDirectory()`判断路径是否为文件夹时,需要特别注意:该方法只能判断已存在的文... 目录Jahttp://www.chinasem.cnvaWeb-file.isDirectory()遇

CSS弹性布局常用设置方式

《CSS弹性布局常用设置方式》文章总结了CSS布局与样式的常用属性和技巧,包括视口单位、弹性盒子布局、浮动元素、背景和边框样式、文本和阴影效果、溢出隐藏、定位以及背景渐变等,通过这些技巧,可以实现复杂... 一、单位元素vm 1vm 为视口的1%vh 视口高的1%vmin 参照长边vmax 参照长边re

JavaWeb-WebSocket浏览器服务器双向通信方式

《JavaWeb-WebSocket浏览器服务器双向通信方式》文章介绍了WebSocket协议的工作原理和应用场景,包括与HTTP的对比,接着,详细介绍了如何在Java中使用WebSocket,包括配... 目录一、概述二、入门2.1 POM依赖2.2 编写配置类2.3 编写WebSocket服务2.4 浏

CSS3中使用flex和grid实现等高元素布局的示例代码

《CSS3中使用flex和grid实现等高元素布局的示例代码》:本文主要介绍了使用CSS3中的Flexbox和Grid布局实现等高元素布局的方法,通过简单的两列实现、每行放置3列以及全部代码的展示,展示了这两种布局方式的实现细节和效果,详细内容请阅读本文,希望能对你有所帮助... 过往的实现方法是使用浮动加

css渐变色背景|<gradient示例详解

《css渐变色背景|<gradient示例详解》CSS渐变是一种从一种颜色平滑过渡到另一种颜色的效果,可以作为元素的背景,它包括线性渐变、径向渐变和锥形渐变,本文介绍css渐变色背景|<gradien... 使用渐变色作为背景可以直接将渐China编程变色用作元素的背景,可以看做是一种特殊的背景图片。(是作为背

CSS自定义浏览器滚动条样式完整代码

《CSS自定义浏览器滚动条样式完整代码》:本文主要介绍了如何使用CSS自定义浏览器滚动条的样式,包括隐藏滚动条的角落、设置滚动条的基本样式、轨道样式和滑块样式,并提供了完整的CSS代码示例,通过这些技巧,你可以为你的网站添加个性化的滚动条样式,从而提升用户体验,详细内容请阅读本文,希望能对你有所帮助...

css实现图片旋转功能

《css实现图片旋转功能》:本文主要介绍了四种CSS变换效果:图片旋转90度、水平翻转、垂直翻转,并附带了相应的代码示例,详细内容请阅读本文,希望能对你有所帮助... 一 css实现图片旋转90度.icon{ -moz-transform:rotate(-90deg); -webkit-transfo

vue基于ElementUI动态设置表格高度的3种方法

《vue基于ElementUI动态设置表格高度的3种方法》ElementUI+vue动态设置表格高度的几种方法,抛砖引玉,还有其它方法动态设置表格高度,大家可以开动脑筋... 方法一、css + js的形式这个方法需要在表格外层设置一个div,原理是将表格的高度设置成外层div的高度,所以外层的div需要

Vue项目中Element UI组件未注册的问题原因及解决方法

《Vue项目中ElementUI组件未注册的问题原因及解决方法》在Vue项目中使用ElementUI组件库时,开发者可能会遇到一些常见问题,例如组件未正确注册导致的警告或错误,本文将详细探讨这些问题... 目录引言一、问题背景1.1 错误信息分析1.2 问题原因二、解决方法2.1 全局引入 Element