前端 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.js

let i = 1

function 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在项目中的妙用

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/241529.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Yolov5双目测距-双目相机计数及测距教程(附代码)

引言 在计算机视觉领域&#xff0c;Yolov5-Binocular相机距离计数及测距是一个引人注目的研究方向。本教程将为小白用户提供一个简明扼要的学习指南&#xff0c;涵盖了关键步骤&#xff0c;包括标定、公示推倒以及重要的代码片段。 第一步&#xff1a;环境搭建 首先&#x…

论文阅读_反思模型_Reflexion

英文名称: Reflexion: Language Agents with Verbal Reinforcement Learning 中文名称: 反思&#xff1a;具有言语强化学习的语言智能体 文章: http://arxiv.org/abs/2303.11366 代码: https://github.com/noahshinn/reflexion 作者: Noah Shinn (Northeastern University) 日期…

【从零开始学习JAVA集合 | 第一篇】深入解读HashMap源码(含面试题)

目录 目录 前言&#xff1a; HashMap简介&#xff1a; HashMap的常用常量和变量&#xff1a; HashMap的重要考点&#xff1a; HashMap的存储过程&#xff1a; HashMap的扩容过程&#xff1a; HashMap的初始化&#xff1a; 常见面试题&#xff1a; 总结&#xff1a;…

Linux 高级管理,MySQL服务器的构建与维护

实验环境 某公司因业务范围日益扩大&#xff0c;最近订购了一套基于B/S架构的电子商务系统&#xff0c;在正式部署之前&#xff0c;要 求对现有的httpd服务器进行改造&#xff0c;首先需要增加MySQL数据库服务。 需求描述 1. 编译安装MySQL服务器&#xff0c;并添加为mysqld系…

mybatisplus saveBatch版本问题导致CPU打满生产问题定位

一、生产现象 1、16:57 运维告知Push微服务有一台因为CPU被打满&#xff0c;自动重启&#xff0c;询问原因。 2、17:00 查看异常节点CPU轨迹,16:30开始CPU出现异常飙升 3、17:10 结合生产日志错误&#xff0c;以及定时任务运行情况&#xff0c;得出结论&#xff1a; 产品在…

conda的安装及使用 以pycharm 为例

下载 https://docs.conda.io/en/latest/miniconda.html 下载 window版本 74M且下着吧。 安装 一路next或agree &#xff0c;不同意人家也不会按装 。重要的是安装目录 让andconda当老大 pycharm的使用 创建项目时如下图选择 成功后进入项目的Terminal则如下图表示成功

【Pytorch】学习记录分享1——Tensor张量初始化与基本操作

1. 基础资料汇总 资料汇总 pytroch中文版本教程 PyTorch入门教程 B站强推&#xff01;2023公认最通俗易懂的【PyTorch】教程&#xff0c;200集付费课程&#xff08;附代码&#xff09;人工智能_机器 视频 1.PyTorch简介 2.PyTorch环境搭建 basic: python numpy pandas pytroch…

Ubuntu22.04 LTS + CUDA12.3 + CUDNN8.9.7 + PyTorch2.1.1

简介 本文记录Ubuntu22.04长期支持版系统下的CUDA驱动和cuDNN神经网络加速库的安装&#xff0c;并安装PyTorch2.1.1来测试是否安装成功。 安装Ubuntu系统 如果是旧的不支持UEFI启动的主板&#xff0c;请参考本人博客U盘系统盘制作与系统安装&#xff08;详细图解&#xff09…

03 Temporal 详细介绍

前言 在后端开发中&#xff0c;大家是否有遇到如下类型的开发场景 需要处理较多的异步事件需要的外部服务可靠性较低需要记录保存某个对象的复杂状态 在以往的开发过程中&#xff0c;可能更多的直接使用数据库、定时任务、消息队列等作为基础&#xff0c;来解决上面的问题。然…

入门PostgreSQL:安装和设置数据库的完整指南!

下载和安装 PostgreSQL&#xff1a; 访问 PostgreSQL 的官方网站(https://www.postgresql.org/)并下载适合你操作系统的最新版本。 执行安装程序&#xff0c;并按照提示完成安装过程。 在安装过程中&#xff0c;你需要设置超级用户(Superuser)密码&#xff0c;这是用于管理数…

【C++】仿函数在模板中的应用——【默认模板实参】详解(n)

前言 大家好吖&#xff0c;欢迎来到 YY 滴C系列 &#xff0c;热烈欢迎&#xff01; 本章主要内容面向接触过C的老铁 主要内容含&#xff1a; 欢迎订阅 YY滴C专栏&#xff01;更多干货持续更新&#xff01;以下是传送门&#xff01; 目录 一.引入&#xff1a;查看(容器)文档时常…

开发案例:使用 canvas 实现图表系列之折线图

一、功能结构 实现一个公共组件的时候&#xff0c;首先分析一下大概的实现结构以及开发思路&#xff0c;方便我们少走弯路&#xff0c;也可以使组件更加容易拓展&#xff0c;维护性更强。然后我会把功能逐个拆开来讲&#xff0c;这样大家才能学习到更详细的内容。下面简单阐述…

C语言好题分享七(三数之和)

❀❀❀ 文章由不准备秃的大伟原创 ❀❀❀ ♪♪♪ 若有转载&#xff0c;请联系博主哦~ ♪♪♪ ❤❤❤ 致力学好编程的宝藏博主&#xff0c;代码兴国&#xff01;❤❤❤ 三数之和 题目来源LeetCode&#xff1a;刷题传送门 题目&#xff1a;给你一个整数数组 nums &#xff0c;判断…

Linux——MySQL数据库的使用

访问MySQL数据库 MySOL数据库系统也是一个典型的C/S&#xff08;客户端/服务器&#xff09;架构的应用&#xff0c;要访问MySOL数据库 需要使用专门的客户端软件&#xff0c;在Linux系统中&#xff0c;最简单、易用的MySQL.客户端软件是其自带的mysql 命令工具。 登录到MySQL服…

Vue3-13- 【v-for】循环一个对象

说明 v-for 这个东西就很神奇&#xff0c;可以遍历一个对象&#xff0c; 当然&#xff0c;它遍历对象是通过 对象的属性名&#xff0c;遍历对象的属性值。语法格式如下 &#xff1a; v-for"(value,key,index) in objName" value : 属性的值 key &#xff1a;属性的k…

商品规格的实现

在商城项目中购买商品或者添加购物车的时候都会让我们去选择商品的规格,颜色、尺码、风格等,这里把刚做完的此功能代码记录下,方便以后查阅: <template><view><u-navbar title="测试"></u-navbar><view class="content"&g…

多篇整合版:最全电商erp系统接口测试实战

之前我们讲了电商ERP系统接口简介以及如何使用post方式获取接口请求 &#xff0c;今天我们来讲解如何用JMeter实现接口功能、性能测试。 内容&#xff1a; JMeter实现接口功能测试 JMeter实现接口的性能测试 JMeter实现接口功能测试 企业性能测试编写脚本过程&#xff1a;接口…

java学生选课系统 数据库版

首先让我们创建一个数据库 让我们向表中插入数据然后查询它

WSL 配置 Docker 内存和 CPU 资源限制

我用的电脑一共有40G内存&#xff0c;最近发现电脑重启后&#xff0c;VmmemWSL 进程很快就会占用一多半的内存&#xff08;20G&#xff09;&#xff0c;电脑中有多个停止运行的容器&#xff0c;正常启动状态的只有一个 MySQL 服务&#xff0c;通过 docker stats 查看占用内存也…

【详解优先级队列(堆)】

目录 堆的概念 堆的性质 堆的存储方式 堆的创建 堆的向下调整 向下过程(以小堆为例) 向下过程(以大堆为例) 建堆的时间复杂度O(n) 堆的插入与删除 堆的插入 向上调整建堆的时间复杂度O(nlogn) 堆的删除 常见习题 常用接口介绍 PriorityQueue的特性 Pri…