前端 Web Workers 简介

2023-12-11 07:01

本文主要是介绍前端 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/479847

相关文章

vite搭建vue3项目的搭建步骤

《vite搭建vue3项目的搭建步骤》本文主要介绍了vite搭建vue3项目的搭建步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学... 目录1.确保Nodejs环境2.使用vite-cli工具3.进入项目安装依赖1.确保Nodejs环境

Nginx搭建前端本地预览环境的完整步骤教学

《Nginx搭建前端本地预览环境的完整步骤教学》这篇文章主要为大家详细介绍了Nginx搭建前端本地预览环境的完整步骤教学,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录项目目录结构核心配置文件:nginx.conf脚本化操作:nginx.shnpm 脚本集成总结:对前端的意义很多

前端缓存策略的自解方案全解析

《前端缓存策略的自解方案全解析》缓存从来都是前端的一个痛点,很多前端搞不清楚缓存到底是何物,:本文主要介绍前端缓存的自解方案,文中通过代码介绍的非常详细,需要的朋友可以参考下... 目录一、为什么“清缓存”成了技术圈的梗二、先给缓存“把个脉”:浏览器到底缓存了谁?三、设计思路:把“发版”做成“自愈”四、代码

通过React实现页面的无限滚动效果

《通过React实现页面的无限滚动效果》今天我们来聊聊无限滚动这个现代Web开发中不可或缺的技术,无论你是刷微博、逛知乎还是看脚本,无限滚动都已经渗透到我们日常的浏览体验中,那么,如何优雅地实现它呢?... 目录1. 早期的解决方案2. 交叉观察者:IntersectionObserver2.1 Inter

Vue3视频播放组件 vue3-video-play使用方式

《Vue3视频播放组件vue3-video-play使用方式》vue3-video-play是Vue3的视频播放组件,基于原生video标签开发,支持MP4和HLS流,提供全局/局部引入方式,可监听... 目录一、安装二、全局引入三、局部引入四、基本使用五、事件监听六、播放 HLS 流七、更多功能总结在 v

JS纯前端实现浏览器语音播报、朗读功能的完整代码

《JS纯前端实现浏览器语音播报、朗读功能的完整代码》在现代互联网的发展中,语音技术正逐渐成为改变用户体验的重要一环,下面:本文主要介绍JS纯前端实现浏览器语音播报、朗读功能的相关资料,文中通过代码... 目录一、朗读单条文本:① 语音自选参数,按钮控制语音:② 效果图:二、朗读多条文本:① 语音有默认值:②

vue监听属性watch的用法及使用场景详解

《vue监听属性watch的用法及使用场景详解》watch是vue中常用的监听器,它主要用于侦听数据的变化,在数据发生变化的时候执行一些操作,:本文主要介绍vue监听属性watch的用法及使用场景... 目录1. 监听属性 watch2. 常规用法3. 监听对象和route变化4. 使用场景附Watch 的

前端导出Excel文件出现乱码或文件损坏问题的解决办法

《前端导出Excel文件出现乱码或文件损坏问题的解决办法》在现代网页应用程序中,前端有时需要与后端进行数据交互,包括下载文件,:本文主要介绍前端导出Excel文件出现乱码或文件损坏问题的解决办法,... 目录1. 检查后端返回的数据格式2. 前端正确处理二进制数据方案 1:直接下载(推荐)方案 2:手动构造

Vue实现路由守卫的示例代码

《Vue实现路由守卫的示例代码》Vue路由守卫是控制页面导航的钩子函数,主要用于鉴权、数据预加载等场景,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着... 目录一、概念二、类型三、实战一、概念路由守卫(Navigation Guards)本质上就是 在路

uni-app小程序项目中实现前端图片压缩实现方式(附详细代码)

《uni-app小程序项目中实现前端图片压缩实现方式(附详细代码)》在uni-app开发中,文件上传和图片处理是很常见的需求,但也经常会遇到各种问题,下面:本文主要介绍uni-app小程序项目中实... 目录方式一:使用<canvas>实现图片压缩(推荐,兼容性好)示例代码(小程序平台):方式二:使用uni