前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >Web Worker

Web Worker

作者头像
政采云前端团队
发布于 2022-04-27 07:21:43
发布于 2022-04-27 07:21:43
1.1K00
代码可运行
举报
文章被收录于专栏:采云轩采云轩
运行总次数:0
代码可运行

Web Worker https://www.zoo.team/article/web-worker

前言

众所周知,JavaScript 是单线程的语言。当我们面临需要大量计算的场景时(比如视频解码等),UI 线程就会被阻塞,甚至浏览器直接卡死。现在前端遇到大量计算的场景越来越多,为了有更好的体验,HTML5 中提出了 Web Worker 的概念。Web Worker 可以使脚本运行在新的线程中,它们独立于主线程,可以进行大量的计算活动,而不会影响主线程的 UI 渲染。当计算结束之后,它们可以把结果发送给主线程,从而形成了高效、良好的用户体验。Web Worker 是一个统称,具体可以细分为普通的 Worker、SharedWorker 和 ServiceWorker 等,接下来我们一一介绍其使用方法和适合的场景。

普通 Worker
  1. 创建 Worker 通过 new 的方式来生成一个实例,参数为 url 地址,该地址必须和其创建者是同源的。
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const worker = new Worker('./worker.js'); // 参数是 url,这个 url 必须与创建者同源 
  1. Worker 的方法
  • onmessage 主线程中可以在 Worker 上添加 onmessage 方法,用于监听 Worker 的信息。 示例:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const worker = new Worker('./worker.js');
worker.onmessage = function (messageEvent) {
 console.log(messageEvent)
} 
  • onmessageerror 主线程中可以在 Worker 上添加 onmessageerror 方法,用于监听 Worker 的错误信息。 示例:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const worker = new Worker('./worker.js');
worker.onmessageerror = function (messageEvent) {
 console.log(messageEvent)
} 
  • postMessage() 主线程通过此方法给 Worker 发送消息,发送参数的格式不限(可以是数组、对象、字符串等),可以根据自己的业务选择。 示例:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const worker = new Worker('./worker.js');
worker.postMessage({ type: 'start', payload: { count: 666 } }); // 发送信息给worker
  • terminate() 主线程通过此方法终止 Worker 的运行。 示例:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const worker = new Worker('./worker.js');
worker.terminate();
  1. 通信 Worker 的作用域跟主线程中的 Window 是相互独立的,并且 Worker 中是获取不到 DOM 元素的。所以在 Worker 中你无法使用 Window 变量。取而代之的是可以用 self 来表示全局对象。self 上有哪些方法和属性,感兴趣的小伙伴可以自行输出查看。比较常用的方法是 onmessage、postMessage,主要用来跟主线程进行通信。 示例:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 监听事件,主线程可以通过 postMessage 发送信息过来
self.onmessage = (messageEvent) => {
 const { type, payload } = messageEvent.data;
  switch (type) {
    case 'start':
      // 通过 type 去区分不同的业务逻辑,payload 是传过来的数据
      const result = 0;
      // ....,通过一系列处理之后,把最终的结果发送给主线程
      this.postMessage(result);
      break;
  }
};

这里我们从 messageEvent.data 中获取从主线程传递过来的数据。为了业务的扩展性,这边是以 type 去区分不同的业务,payload 承载数据源,通过处理之后把结果发给主线程。主线程的 onmessage 回调函数中就能收到这个结果了。

  1. Worker 中引用其他脚本的方式

跟常用的 JavaScript 一样,Worker 中也是可以引入其他的模块的。但是方式不太一样,是通过 importScripts 来引入。这边我为了演示,新建了一个 constant.js。在 constant.js 定义了一些变量和函数。

示例:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// Worker.js
importScripts('constant.js');
// 下面就可以获取到 constant.js 中的所有变量了

// constant.js
// 可以在 Worker 中使用
const a = 111;

// 不可以在 Worker 中使用,原因未知
const b = function () {
  console.log('test');
};

// 可以在 Worker 中使用
function c() {
  console.log('test');
}
  1. 调试方法 写代码难免要进行调试。Worker 的调试在浏览器控制台中有专门展示的地方,见下图。
  1. 常见使用场景
    • 一般的视频网站 以优酷为例,当我们开始播放优酷视频的时候,就能看到它会调用 Worker,解码的代码应该写在 Worker 里面。
    • 需要大量计算的网站 比如 imgcook 这个网站,它能在前端解析 sketch 文件,这部分解析的逻辑就写在 Worker 里。
SharedWorker

SharedWorker 是一种特定的 Worker。从它的命名就能知道,它是一种共享数据的 Worker。它可以同时被多个浏览器环境访问。这些浏览器环境可以是多个 window, iframes 或者甚至是多个 Worker,只要这些 Workers 处于同一主域。为跨浏览器 tab 共享数据提供了一种解决方案。

  1. 创建 SharedWorker 创建的方法跟上面普通 Worker 完全一模一样。
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const worker = new SharedWorker("./shareWorker.js"); // 参数是 url,这个 url 必须与创建者同源 
  1. SharedWorker 的方法 SharedWorker 的方法都在 port 上,这是它与普通 Worker 不同的地方。
  • port.onmessage 主线程中可以在 worker 上添加 onmessage 方法,用于监听 SharedWorker 的信息 示例:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const sharedWorker = new SharedWorker('./shareWorker.js');
sharedWorker.port.onmessage = function (messageEvent) {
  console.log(messageEvent)
} 
  • port.postMessage() 主线程通过此方法给 SharedWorker 发送消息,发送参数的格式不限 示例:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const sharedWorker = new SharedWorker('./shareWorker.js');
sharedWorker.port.postMessage({ type: 'increase', payload: { count: 666 } });
  • port.start() 主线程通过此方法开启 SharedWorker 之间的通信 示例:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const sharedWorker = new SharedWorker('./shareWorker.js');
sharedWorker.port.start()
  • port.close() 主线程通过此方法关闭 SharedWorker 示例:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const sharedWorker = new SharedWorker('./shareWorker.js');
sharedWorker.port.close()
  1. 通信 SharedWorker 跟普通的 Worker 一样,可以用 self 来表示全局对象。不同之处是,它需要等 port 连接成功之后,利用 port 的onmessage、postMessage,来跟主线程进行通信。当你打开多个窗口的时候,SharedWorker 的作用域是公用的,这也是其特点。 示例:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// index.js
const worker = new SharedWorker('./shareWorker.js');

worker.port.start(); // 开启端口

// 发送信息给 shareWorker
worker.port.postMessage({ type: 'increase', payload: { count: 666 } }); 

// 接受 shareWorker 发过来的数据
worker.port.onmessage = function (val) {
  console.log(val.data)
};

// shareWorker.js
let count = 666;

port.onmessage = (messageEvent) => {
  const { type, payload } = messageEvent.data;

  switch (type) {
    case 'increase':
      port.postMessage(++count);
      break;
    case 'decrease':
      port.postMessage(--count);
      break;
  }
};
  1. Worker 中引用其他脚本 这个与普通的 Worker 方法一样,使用 importScripts
  2. 调试方法 在浏览器中查看和调试 SharedWorker 的代码,需要输入 chrome://inspect/
ServiceWorker

ServiceWorker 一般作为 Web 应用程序、浏览器和网络之间的代理服务。他们旨在创建有效的离线体验,拦截网络请求,以及根据网络是否可用采取合适的行动,更新驻留在服务器上的资源。他们还将允许访问推送通知和后台同步 API

  1. 创建 ServiceWorker
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// index.js
if ('serviceWorker' in navigator) {
  window.addEventListener('load', function () {
    navigator.serviceWorker
      .register('./serviceWorker.js', { scope: '/page/' })
      .then(
      function (registration) {
        console.log('ServiceWorker registration successful with scope: ',
                    registration.scope);
      },
      function (err) {
        console.log('ServiceWorker registration failed: ', err);
      }
    );
  });
}

只要创建了 ServiceWorker,不管这个创建 ServiceWorker 的 html 是否打开,这个 ServiceWorker 是一直存在的。它会代理范围是根据 scope 决定的,如果没有这个参数,则其代理范围是创建目录同级别以及子目录下所有页面的网络请求。代理的范围可以通过 registration.scope 查看。

  1. 安装 ServiceWorker
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// serviceWorker.js
const CACHE_NAME = 'cache-v1';
// 需要缓存的文件
const urlsToCache = [
  '/style/main.css',
  '/constant.js',
  '/serviceWorker.html',
  '/page/index.html',
  '/serviceWorker.js',
  '/image/131.png',
];
self.oninstall = (event) => {
  event.waitUntil(
    caches
    .open(CACHE_NAME) // 这返回的是 promise
    .then(function (cache) {
      return cache.addAll(urlsToCache); // 这返回的是 promise
    })
  );
};

在上述代码中,我们可以看到,在 install 事件的回调中,我们打开了名字为 cache-v1 的缓存,它返回的是一个 promise。在打开缓存之后,我们需要把要缓存的文件 add 进去,基本上所有类型的资源都可以进行缓存,例子中缓存了 css、js、html、png。如果所有缓存数据都成功,就表示 ServiceWorker 安装成功;如果控制台提示 Uncaught (in promise) TypeError: Failed to execute 'Cache' on 'addAll': Request failed,则表示安装失败。

  1. 缓存和返回请求
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
self.onfetch = (event) => {
  event.respondWith(
    caches
    .match(event.request) // 此方法从服务工作线程所创建的任何缓存中查找缓存的结果
    .then(function (response) {
      // response 为匹配到的缓存资源,如果没有匹配到则返回 undefined,需要 fetch 资源
      if (response) {
        return response;
      }
      return fetch(event.request);
    })
  );
};

在 fetch 事件的回调中,我们去匹配 cache 中的资源。如果匹配到,则使用缓存资源;没有匹配到则用 fetch 请求。正因为 ServiceWorker 可以代理网络请求,所以为了安全起见,规范中规定它只能在 https 和 localhost 下才能开启。

  1. 调试方法 在浏览器中查看和调试 ServiceWorker 的代码,需要输入 chrome://inspect/#service-workers
  1. 演示效果

上面代码中,我缓存了 131.png。切换到离线模式,131 图片还是能显示,134.png 就获取不到了。

看到这里,大家可能会有疑惑了。这个图片它存到哪里去了?实际上它会把文件自动存到浏览器的 Cache Storage 中。我们打开浏览器可以看到。

  1. 常见使用场景 缓存资源文件,加快渲染速度 这个我们以语雀为例。我们在打开语雀网站的时候,可以看到它使用 ServiceWorker 缓存了很多 css、js 文件,从而达到优化的效果。

总结

类型

Worker

SharedWorker

ServiceWorker

通信方式

postMessage

port.postMessage

单向通信,通过addEventListener 监听serviceWorker 的状态

使用场景

适合大量计算的场景

适合跨 tab、iframes之间共享数据

缓存资源、网络优化

兼容性

>= IE 10>= Chrome 4

不支持 IE、Safari、Android、iOS>= Chrome 4

不支持 IE>= Chrome 40

本文介绍了 3 种 Worker,他们分别适合不同的场景,总结如上面表格。普通的 Worker 可以在需要大量计算的时候使用,创建新的线程可以降低主线程的计算压力,不会导致 UI 卡顿。SharedWorker 主要是为不同的 window、iframes 之间共享数据提供了另外一个解决方案。ServiceWorker 可以缓存资源,提供离线服务或者是网络优化,加快 Web 应用的开启速度,更多是优化体验方面的。

示例代码:https://github.com/Pulset/Web-Worker

参考文献

  • 在网络应用中添加服务工作线程和离线功能(https://developers.google.com/web/fundamentals/codelabs/offline)
  • Service worker overview(https://developer.chrome.com/docs/workbox/service-worker-overview/)
  • Workers(https://developer.mozilla.org/zh-CN/docs/Web/API/Worker)
  • SharedWorker(https://developer.mozilla.org/zh-CN/docs/Web/API/SharedWorker)
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-04-26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 政采云技术 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
使用 COSFS 挂载 COS 到云服务器节约空间
作者介绍 我是技术小白:机械电子工程专业大四学生,业余时间喜欢折腾。 本文将介绍使用 COSFS 工具将 WordPress/NextCloud 的文件目录挂载到 COS 存储桶的方法,以达到节约服务器硬盘空间的目的。 Wordpress 的数据存放在安装目录下的 wp-content/uploads 文件夹,Nextcloud 的数据存放在安装目录下的 data 文件夹,里面存储着网站的媒体文件,占据的磁盘空间特别大。 为了节省磁盘空间,就将腾讯云对象存储(COS)挂载到他们的数据目录下,存储数据
云存储
2020/07/10
4.6K0
COS对象存储数据冗余备份方案
一般意义上,备份指的是数据备份或系统备份,容灾指的是不在同一机房的数据备份或应用系统备份。备份采用备份软件技术实现,而容灾通过复制或镜像软件实现,两者的根本区别在于:
wainsun
2023/03/07
3.8K0
COS对象存储数据冗余备份方案
腾讯云COS对象存储占据数据容灾C位
然而,随着企业核心业务逐渐从线下迁移到云上,客户提出了更高的要求。如何确保云上业务的高可用、数据的高可靠,这对云厂商提出了新的挑战。
云存储
2021/01/20
3.6K0
腾讯云COS对象存储占据数据容灾C位
腾讯云对象存储COS安全方案介绍
​相信所有企业和个人开发者在选用云存储产品时都把数据安全作为重要考量标准。 本文介绍了用户如何使用腾讯云对象存储COS的事前防护、事中监控、事后追溯三个手段来保证自己的数据安全。
云存储
2020/03/03
7.2K0
【玩转腾讯云】使用 COSFS 挂载 COS 到云服务器节约空间
本文将介绍使用 COSFS 工具 将 WordPress/NextCloud 的文件目录挂载到 COS 存储桶的方法,以达到节约服务器硬盘空间的目的。
我是技术小白
2020/04/15
7.3K0
【玩转腾讯云】云函数实时备份存储桶 A 中文件到存储桶 B
【注意】发现程序 bug ,假如从 A 存储桶备份至 B 存储桶,只能对上传到 A 中根目录的文件进行实时备份,对上传到 A 中一级及以上目录的文件,备份失败并报错。
我是技术小白
2020/04/15
3.2K0
数据不再玩失踪?COS实用案例之“备份”
一周前,一位刚刚投身教育事业的朋友半夜发朋友圈哭诉到,因为笔记本突发故障,辛苦准备了一个月的教案,全部化为乌有,又要重新“历劫”了。
云存储
2020/04/09
1.7K0
数据不再玩失踪?COS实用案例之“备份”
腾讯云ES集群通过COS实现跨地域备份与恢复
在日常开发及运维工作中,我们经常会遇到一些内外部的客户希望将不同地域的es集群迁移到另外一个地域。例如有的客户es集群原来是在北京地域,由于一些原因,现在想要将集群迁移到上海地域来。下面我们就详细介绍下借助腾讯云COS和es的snapshot功能来实现跨地域的数据迁移。
吴容
2020/07/29
2.7K0
腾讯云ES集群通过COS实现跨地域备份与恢复
数据误删?别怕!COS防误删和误删恢复攻略请查收
在云存储领域,数据的安全性始终是悬在头顶的达摩克利斯之剑。长期以来,腾讯云对象存储服务(COS)一直致力于数据安全的探索和实践,以保障数据的安全性和完整性。对象存储COS准备了一份“防误删”和“误删恢复”攻略给大家,本文将深入介绍这两部分。
云存储
2024/06/03
2660
数据误删?别怕!COS防误删和误删恢复攻略请查收
数据持久性是如何炼成的——对象存储容灾技术解析
存储系统作为支撑人工智能发展的关键基础设施,不仅需要提供弹性、海量数据存储能力,还要保证数据的安全性和可靠性,以确保业务的核心数据资产得以持久存储,大模型时代对海量数据的安全可靠存储提出了更高的要求。
云存储
2025/02/10
730
数据持久性是如何炼成的——对象存储容灾技术解析
企业业务上云,云上数据的容灾备份和高可用性如何解决呢???
数据中心运行突发故障(如:天灾不可避免的灾难)是无法预测的,计算机里的数据就像扫雷游戏一样,十面埋伏充满雷区,随时都有可能Game Over,容灾备份就是数据安全的最后防线,是你可以避免由数据中心发生故障而丢失数据引发的不可挽回的局面。
云存储
2020/05/26
1K0
企业业务上云,云上数据的容灾备份和高可用性如何解决呢???
腾讯云ES集群通过COS实现跨地域备份与恢复
在日常开发及运维工作中,我们经常会遇到一些内外部的客户希望将不同地域的es集群迁移到另外一个地域。例如有的客户es集群原来是在北京地域,由于一些原因,现在想要将集群迁移到上海地域来。下面我们就详细介绍下借助腾讯云COS和es的snapshot功能来实现跨地域的数据迁移。
腾讯云大数据
2021/01/08
1.2K0
腾讯云ES集群通过COS实现跨地域备份与恢复
使用COS实现云数据库MySQL备份文件的多元化管理
云数据库 MySQL(TencentDB for MySQL)是腾讯云基于开源数据库 MySQL 专业打造的高性能分布式数据存储服务,让用户能够在云中更轻松地设置、操作和扩展关系数据库。同时云数据库MySQL集成了数据库的备份功能,可以针对数据库实现数据库的自动数据备份、手动数据备份以及日志备份。
HuiG
2021/03/17
2.4K0
幻兽帕鲁服务器数据备份(云备份)
搭建幻兽帕鲁个人服务器,最近不少用户碰到内存不足、游戏坏档之类的问题。将游戏存档进行云备份,不占用服务器空间,需要时支持快速恢复。
lucia
2024/01/23
9.4K32
腾讯云对象存储 COS 高可用解决方案,都在这里了!
上一篇内容我们说到了 COS 是什么“要对象存储做什么,我有女朋友就够了!”的文章。本文将着重介绍如何尽可能的提高腾讯云对象存储 COS 的可用性。
云存储
2019/12/06
2.7K0
腾讯云对象存储 COS 高可用解决方案,都在这里了!
如何将您的Git存储库备份到腾讯云COS
依赖源代码存储库进行版本控制是一种最佳的方法,当代码更改导致应用程序崩溃或行为不正常时,可以恢复运行。但是,如果发生诸如不小心删除分支或无法访问存储库等严重性事件,我们应该利用其他更高级恢复策略。
水门
2018/08/13
4.7K0
玩转腾讯云对象存储 - COS 插件
本文由作者在 “开箱吧腾讯云 - 加码生态 / Get 对象存储操作新姿势” 专场演讲稿改写而成。
若海
2022/12/06
10K0
玩转腾讯云对象存储 - COS 插件
【对象存储COS】使用COS自动数据备份,解放硬盘空间
视频,照片,录音......诸如此类的文件在手机电脑里,永远是不断增多,不断占用的东西,每次空间告急时,都要花一大片时间去整理,删除照片释放这宝贵的空间,“这个删,这个删不删呢?可能以后要用......”,挑选照片还真是一个费时费力还费心的活。
Ar-Sr-Na
2024/06/03
2560
IDC、友商云数据上云(COS)最佳实践
本文从通用的数据上云场景,以及友商云数据迁移场景出发,介绍基于腾讯云对象存储(COS)的上云步骤,包括迁移前的环境准备工作,云上的配置与迁移工具的实施,数据的一致性校验,云上业务的切换与验证。
wainsun
2021/08/18
2.3K0
IDC、友商云数据上云(COS)最佳实践
腾讯云主机安装COSFS工具并使用COS对象存储
对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。
yuanfan2012
2021/01/28
3.7K0
推荐阅读
相关推荐
使用 COSFS 挂载 COS 到云服务器节约空间
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档