你不知道的 Web Workers (上)[7.8K 字 | 多图预警]

阅读完本文你将学到如下知识:javascript

  • 进程与线程的区别:进程与线程的概念及单线程与多线程;
  • 浏览器内核的相关知识:GUI 渲染线程、JavaScript 引擎线程、事件触发线程等;
  • Web Workers 是什么:Web Workers 的限制与能力及主线程与 Web Workers 之间如何通讯;
  • Web Workers 的分类:Dedicated Worker、Shared Worker 和 Service Workers;
  • Web Workers API:Worker 构造函数及如何观察 Dedicated Worker 等。

阅读阿宝哥近期热门文章(感谢掘友的鼓励与支持🌹🌹🌹):html

下面咱们开始步入正题,为了让你们可以更好地理解和掌握 Web Workers,在正式介绍 Web Workers 以前,咱们先来介绍一些与 Web Workers 相关的基础知识。前端

1、进程与线程的区别

在介绍进程与线程的概念前,咱们先来看个进程与线程之间关系形象的比喻:java

如上图所示,进程是一个工厂,它有独立的资源,线程是工厂中的工人,多个工人协做完成任务,工人之间共享工厂内的资源,好比工厂内的食堂或餐厅。此外,工厂(进程)与工厂(进程)之间是相互独立的。为了让你们可以更直观地理解进程与线程的区别,咱们继续来看张图:webpack

由上图可知,操做系统会为每一个进程分配独立的内存空间,一个进程由一个或多个线程组成,同个进程下的各个线程之间共享程序的内存空间。相信经过前面两张图,小伙伴们对进程和线程之间的区别已经有了必定的了解,那么实际状况是否是这样呢?这里咱们打开 macOS 操做系统下的活动监视器,来看一下写做本文时全部进程的状态:git

经过上图可知,咱们经常使用的软件,好比微信和搜狗输入法都是一个独立的进程,拥有不一样的 PID(进程 ID),并且图中的每一个进程都含有多个线程,以微信进程为例,它就含有 36 个线程。那么什么是进程和线程呢?下面咱们来介绍进程和线程的概念。github

1.1 进程的概念

进程(英语:process),是指计算机中已运行的程序。进程曾经是分时系统的基本运做单位。在面向进程设计的系统(如早期的 UNIX,Linux 2.4 及更早的版本)中,进程是程序的基本执行实体;在面向线程设计的系统(如当代多数操做系统、Linux 2.6 及更新的版本)中,进程自己不是基本运行单位,而是线程的容器。web

程序自己只是指令、数据及其组织形式的描述,进程才是程序的真正运行实例。若干进程有可能与同一个程序相关系,且每一个进程皆能够同步或异步的方式独立运行。现代计算机系统可在同一段时间内以进程的形式将多个程序加载到存储器中,并借由时间共享(或称时分复用),以在一个处理器上表现出同时运行的感受。ajax

1.2 线程的概念

线程(英语:thread)是操做系统可以进行运算调度的最小单位。大部分状况下,它被包含在进程之中,是进程中的实际运做单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中能够并发多个线程,每条线程并行执行不一样的任务。chrome

线程是独立调度和分派的基本单位。线程能够为操做系统内核调度的内核线程,如 Win32 线程;由用户进程自行调度的用户线程,如 Linux 平台的 POSIX Thread;或者由内核与用户进程,如 Windows 7 的线程,进行混合调度。

同一进程中的多条线程将共享该进程中的所有系统资源,如虚拟地址空间,文件描述符和信号处理等等。 但同一进程中的多个线程有各自的调用栈(call stack),本身的寄存器环境(register context),本身的线程本地存储(thread-local storage)。一个进程能够有不少线程,每条线程并行执行不一样的任务。

1.3 单线程与多线程

若是一个进程只有一个线程,咱们称之为单线程。单线程在程序执行时,所走的程序路径按照连续顺序排下来,前面的必须处理好,后面的才会执行。单线程处理的优势:同步应用程序的开发比较容易,但因为须要在上一个任务完成后才能开始新的任务,因此其效率一般比多线程应用程序低。

若是完成同步任务所用的时间比预计时间长,应用程序可能会不响应。针对这个问题,咱们能够考虑使用多线程,即在进程中使用多个线程,这样就能够处理多个任务。

对于 Web 开发者熟悉的 JavaScript 来讲,它运行在浏览器中,是单线程的,每一个窗口一个 JavaScript 线程,既然是单线程的,在某个特定的时刻,只有特定的代码可以被执行,其它的代码会被阻塞。

JS 中实际上是没有线程概念的,所谓的单线程也只是相对于多线程而言。JS 的设计初衷就没有考虑这些,针对 JS 这种不具有并行任务处理的特性,咱们称之为 “单线程”。 —— 来自知乎 “如何证实 JavaScript 是单线程的?” @云澹的回答

其实在浏览器内核(渲染进程)中除了 JavaScript 引擎线程以外,还含有 GUI 渲染线程、事件触发线程、定时触发器线程等。所以对于浏览器的渲染进程来讲,它是多线程的。接下来咱们来简单介绍浏览器内核。

2、浏览器内核

浏览器最核心的部分是 “Rendering Engine”,即 “渲染引擎”,不过咱们通常习惯将之称为 “浏览器内核”。 它主要包括如下线程:

下面咱们来分别介绍渲染进程中的每一个线程。

2.1 GUI 渲染线程

GUI 渲染线程负责渲染浏览器界面,解析 HTML,CSS,构建 DOM 树和 RenderObject 树,布局和绘制等。当界面须要重绘(Repaint)或因为某种操做引起回流(Reflow)时,该线程就会执行。

2.2 JavaScript 引擎线程

JavaScript 引擎线程负责解析 JavaScript 脚本并运行相关代码。 JavaScript 引擎一直等待着任务队列中任务的到来,而后进行处理,一个Tab页(Renderer 进程)中不管何时都只有一个 JavaScript 线程在运行 JavaScript 程序。

须要注意的是,GUI 渲染线程与 JavaScript 引擎线程是互斥的,因此若是 JavaScript 执行的时间过长,这样就会形成页面的渲染不连贯,致使页面渲染被阻塞。

2.3 事件触发线程

当一个事件被触发时该线程会把事件添加到待处理队列的队尾,等待 JavaScript 引擎的处理。这些事件能够是当前执行的代码块如定时任务、也可来自浏览器内核的其余线程如鼠标点击、AJAX 异步请求等,但因为 JavaScript 引擎是单线程的,全部这些事件都得排队等待 JavaScript 引擎处理。

2.4 定时触发器线程

浏览器定时计数器并非由 JavaScript 引擎计数的,这是由于 JavaScript 引擎是单线程的,若是处于阻塞线程状态就会影响记计时的准确,因此经过单独线程来计时并触发定时是更为合理的方案。咱们平常开发中经常使用的 setInterval 和 setTimeout 就在该线程中。

2.5 Http 异步请求线程

在 XMLHttpRequest 在链接后是经过浏览器新开一个线程请求, 将检测到状态变动时,若是设置有回调函数,异步线程就产生状态变动事件放到 JavaScript 引擎的处理队列中等待处理。

前面咱们已经知道了,因为 JavaScript 引擎与 GUI 渲染线程是互斥的,若是 JavaScript 引擎执行了一些计算密集型或高延迟的任务,那么会致使 GUI 渲染线程被阻塞或拖慢。那么如何解决这个问题呢?嘿嘿,固然是使用本文的主角 —— Web Workers。

3、Web Workers 是什么

Web Worker 是 HTML5 标准的一部分,这一规范定义了一套 API,它容许一段 JavaScript 程序运行在主线程以外的另一个线程中。Web Worker 的做用,就是为 JavaScript 创造多线程环境,容许主线程建立 Worker 线程,将一些任务分配给后者运行。

在主线程运行的同时,Worker 线程在后台运行,二者互不干扰。等到 Worker 线程完成计算任务,再把结果返回给主线程。这样的好处是,能够在独立线程中处理一些计算密集型或高延迟的任务,从而容许主线程(一般是 UI 线程)不会所以被阻塞或拖慢。

(图片来源:https://thecodersblog.com/web-worker-and-implementation/)

3.1 Web Workers 的限制与能力

一般状况下,你能够在 Worker 线程中运行任意的代码,但注意存在一些例外状况,好比:直接在 worker 线程中操纵 DOM 元素,或使用 window 对象中的某些方法和属性。 大部分 window 对象的方法和属性是可使用的,包括 WebSockets,以及诸如 IndexedDB 和 FireFox OS 中独有的 Data Store API 这一类数据存储机制。

下面咱们以 Chrome 和 Opera 所使用的 Blink 渲染引擎为例,介绍该渲染引擎下 Web Worker 中所支持的经常使用 APIs:

  • Cache:Cache 接口为缓存的 Request / Response 对象对提供存储机制,例如,做为ServiceWorker 生命周期的一部分。
  • CustomEvent:用于建立自定义事件。
  • Fetch:Fetch API 提供了一个获取资源的接口(包括跨域请求)。任何使用过 XMLHttpRequest 的人都能轻松上手,并且新的 API 提供了更强大和灵活的功能集。
  • Promise:Promise 对象表明了将来将要发生的事件,用来传递异步操做的消息。
  • FileReader:FileReader 对象容许 Web 应用程序异步读取存储在用户计算机上的文件(或原始数据缓冲区)的内容,使用 File 或 Blob 对象指定要读取的文件或数据。
  • IndexedDB:IndexedDB 是一种底层 API,用于客户端存储大量结构化数据,包括文件/二进制大型对象(blobs)。
  • WebSocket:WebSocket 对象提供了用于建立和管理 WebSocket 链接,以及能够经过该链接发送和接收数据的 API。
  • XMLHttpRequest:XMLHttpRequest(XHR)对象用于与服务器交互。经过 XMLHttpRequest 能够在不刷新页面的状况下请求特定 URL,获取数据。这容许网页在不影响用户操做的状况下,更新页面的局部内容。

更多信息请参见: Functions and classes available to workers

3.2 主线程与 Web Workers 之间的通讯

主线程和 Worker 线程相互之间使用 postMessage() 方法来发送信息,而且经过 onmessage 这个事件处理器来接收信息。数据的交互方式为传递副本,而不是直接共享数据。主线程与 Worker 线程的交互方式以下图所示:

(图片来源:https://viblo.asia/p/simple-web-workers-workflow-with-webpack-3P0lPkobZox)

除此以外,Worker 还能够经过 XMLHttpRequest 来访问网络,只不过 XMLHttpRequest 对象的 responseXMLchannel 这两个属性的值将老是 null

4、Web Workers 的分类

Web Worker 规范中定义了两类工做线程,分别是专用线程 Dedicated Worker 和共享线程 Shared Worker,其中,Dedicated Worker 只能为一个页面所使用,而 Shared Worker 则能够被多个页面所共享。

4.1 Dedicated Worker

一个专用 Worker 仅仅能被生成它的脚本所使用,其浏览器支持状况以下:

(图片来源:[https://caniuse.com/#search=Web%20Workers](https://caniuse.com/#search=Web Workers))

须要注意的是,因为 Web Worker 有同源限制,因此在进行本地调试或运行如下示例的时候,须要先启动本地服务器,直接使用 file:// 协议打开页面的时候,会抛出如下异常:

Uncaught DOMException: Failed to construct 'Worker': 
Script at 'file:///**/*.js' cannot be accessed from origin 'null'. 复制代码
4.1.1 专用线程 Dedicated Worker:Ping/Pong

index.html

<!DOCTYPE html>
<html lang="zh-CN">  <head>  <meta charset="UTF-8" />  <meta name="viewport" content="width=device-width, initial-scale=1.0" />  <title>专用线程 Dedicated Worker —— Ping/Pong</title>  </head>  <body>  <h3>阿宝哥:专用线程 Dedicated Worker —— Ping/Pong</h3>  <script>  if (window.Worker) {  let worker = new Worker("dw-ping-pong.js");  worker.onmessage = (e) =>  console.log(`Main: Received message - ${e.data}`);  worker.postMessage("PING");  } else {  console.log("呜呜呜,不支持 Web Worker");  }  </script>  </body> </html> 复制代码

dw-ping-pong.js

onmessage = (e) => {
 console.log(`Worker: Received message - ${e.data}`);  postMessage("PONG"); } 复制代码

以上代码成功运行后,浏览器控制台会输出如下结果:

Worker: Received message - PING
Main: Received message - PONG 复制代码

每一个 Web Worker 均可以建立本身的子 Worker,这容许咱们将任务分散到多个线程。建立子 Worker 也很简单,具体咱们来看个例子。

4.1.2 专用线程 Dedicated Sub Worker:Ping/Pong

index.html

<!DOCTYPE html>
<html lang="zh-CN">  <head>  <meta charset="UTF-8" />  <meta name="viewport" content="width=device-width, initial-scale=1.0" />  <title>专用线程 Dedicated Sub Worker —— Ping/Pong</title>  </head>  <body>  <h3>阿宝哥:专用线程 Dedicated Sub Worker —— Ping/Pong</h3>  <script>  if (window.Worker) {  let worker = new Worker("dw-ping-pong.js");  worker.onmessage = (e) =>  console.log(`Main: Received message - ${e.data}`);  worker.postMessage("PING");  } else {  console.log("呜呜呜,不支持 Web Worker");  }  </script>  </body> </html> 复制代码

dw-ping-pong.js

onmessage = (e) => {
 console.log(`Worker: Received message - ${e.data}`);  setTimeout(() => {  let worker = new Worker("dw-sub-ping-pong.js");  worker.onmessage = (e) => console.log(`Worker: Received from sub worker - ${e.data}`);  worker.postMessage("PING");  }, 1000);  postMessage("PONG"); }; 复制代码

dw-sub-ping-pong.js

onmessage = (e) => {
 console.log(`Sub Worker: Received message - ${e.data}`);  postMessage("PONG"); }; 复制代码

以上代码成功运行后,浏览器控制台会输出如下结果:

Worker: Received message - PING
Main: Received message - PONG Sub Worker: Received message - PING Received from sub worker - PONG 复制代码
4.1.3 专用线程 Dedicated Worker:importScripts

其实在 Web Worker 中,咱们也可使用 importScripts 方法将一个或多个脚本同步导入到 Web Worker 的做用域中。一样咱们来举个例子。

index.html

<!DOCTYPE html>
<html lang="en">  <head>  <meta charset="UTF-8" />  <meta name="viewport" content="width=device-width, initial-scale=1.0" />  <title>专用线程 Dedicated Worker —— importScripts</title>  </head>  <body>  <h3>阿宝哥:专用线程 Dedicated Worker —— importScripts</h3>  <script>  let worker = new Worker("worker.js");  worker.onmessage = (e) => console.log(`Main: Received kebab case message - ${e.data}`);  worker.postMessage(  "Hello, My name is semlinker."  );  </script>  </body> </html> 复制代码

worker.js

importScripts("https://cdn.bootcdn.net/ajax/libs/lodash.js/4.17.15/lodash.min.js");
 onmessage = ({ data }) => {  postMessage(_.kebabCase(data)); }; 复制代码

以上代码成功运行后,浏览器控制台会输出如下结果:

Main: Received kebab case message - hello-my-name-is-semlinker
复制代码
4.1.4 专用线程 Dedicated Worker:inline-worker

在前面的例子中,咱们都是使用外部的 Worker 脚原本建立 Web Worker 对象。其实你也能够经过 Blob URL 或 Data URL 的形式来建立 Web Worker,这类 Worker 也被称为 Inline Worker。

1. 使用 Blob URL 建立 Inline Worker

Blob URL/Object URL 是一种伪协议,容许 Blob 和 File 对象用做图像,下载二进制数据连接等的 URL 源。在浏览器中,咱们使用 URL.createObjectURL 方法来建立 Blob URL,该方法接收一个 Blob 对象,并为其建立一个惟一的 URL,其形式为 blob:<origin>/<uuid>,对应的示例以下:

blob:https://example.org/40a5fb5a-d56d-4a33-b4e2-0acf6a8e5f641
复制代码

浏览器内部为每一个经过 URL.createObjectURL 生成的 URL 存储了一个 URL → Blob 映射。所以,此类 URL 较短,但能够访问 Blob。生成的 URL 仅在当前文档打开的状态下才有效。它容许引用 <img><a> 中的 Blob,但若是你访问的 Blob URL 再也不存在,则会从浏览器中收到 404 错误。

const url = URL.createObjectURL(
 new Blob([`postMessage("Dedicated Worker created by Blob")`]) );  let worker = new Worker(url); worker.onmessage = (e) =>  console.log(`Main: Received message - ${e.data}`); 复制代码

除了在代码中使用字符串动态建立 Worker 脚本,也能够把 Worker 脚本使用类型为 javascript/workerscript 标签内嵌在页面中,具体以下所示:

<script id="myWorker" type="javascript/worker">  self['onmessage'] = function(event) {  postMessage('Hello, ' + event.data.name + '!');  }; </script> 复制代码

接着就是经过 script 对象的 textContent 属性来获取对应的内容,而后使用 Blob API 和 createObjectURL API 来最终建立 Web Worker:

<script>  let workerScript = document.querySelector('#myWorker').textContent;  let blob = new Blob(workerScript, {type: "text/javascript"});  let worker = new Worker(URL.createObjectURL(blob)); </script> 复制代码

2. 使用 Data URL 建立 Inline Worker

Data URLs 由四个部分组成:前缀(data:)、指示数据类型的 MIME 类型、若是非文本则为可选的 base64 标记、数据自己:

data:[<mediatype>][;base64],<data>
复制代码

mediatype 是个 MIME 类型的字符串,例如 "image/jpeg" 表示 JPEG 图像文件。若是被省略,则默认值为 text/plain;charset=US-ASCII。若是数据是文本类型,你能够直接将文本嵌入(根据文档类型,使用合适的实体字符或转义字符)。若是是二进制数据,你能够将数据进行 base64 编码以后再进行嵌入。

const url = `data:application/javascript,${encodeURIComponent(  `postMessage("Dedicated Worker created by Data URL")` )}`;  let worker = new Worker(url); worker.onmessage = (e) =>  console.log(`Main: Received message - ${e.data}`); 复制代码

4.2 Shared Worker

一个共享 Worker 是一种特殊类型的 Worker,能够被多个浏览上下文访问,好比多个 windows,iframes 和 workers,但这些浏览上下文必须同源。相比 dedicated workers,它们拥有不一样的做用域。其浏览器支持状况以下:

(图片来源:[https://caniuse.com/#search=Web%20Workers](https://caniuse.com/#search=Web Workers))

与常规的 Worker 不一样,首先咱们须要使用 onconnect 方法等待链接,而后咱们得到一个端口,该端口是咱们与窗口之间的链接。

4.2.1 共享线程 Shared Worker:点赞计数器

index.html

<!DOCTYPE html>
<html lang="zh-CN">  <head>  <meta charset="UTF-8" />  <meta name="viewport" content="width=device-width, initial-scale=1.0" />  <title>共享线程 Shared Worker</title>  </head>  <body>  <h3>阿宝哥:共享线程 Shared Worker</h3>  <button id="likeBtn">点赞</button>  <p>阿宝哥一共收获了<span id="likedCount">0</span>个👍</p>  <script>  let likes = 0;  let likeBtn = document.querySelector("#likeBtn");  let likedCountEl = document.querySelector("#likedCount");   let worker = new SharedWorker("shared-worker.js");  worker.port.start();   likeBtn.addEventListener("click", function () {  worker.port.postMessage("like");  });   worker.port.onmessage = function (val) {  likedCountEl.innerHTML = val.data;  };  </script>  </body> </html> 复制代码

shared-worker.js

let a = 666;
 console.log("shared-worker"); onconnect = function (e) {  var port = e.ports[0];   port.onmessage = function () {  port.postMessage(a++);  }; }; 复制代码

在 Shared Worker 的示例页面上有一个 点赞 按钮,每次点击时点赞数会加 1。首先你新开一个窗口,而后点击几回。而后新开另外一个窗口继续点击,这时你会发现当前页面显示的点赞数是基于前一个页面的点赞数继续累加。

4.2.2 调试 Shared Workers

在实际项目开发过程当中,若须要调试 Shared Workers 中的脚本,能够经过 chrome://inspect 来进行调试,具体步骤以下图所示:

4.3 Service Workers

Service workers 本质上充当 Web 应用程序与浏览器之间的代理服务器,也能够在网络可用时做为浏览器和网络间的代理。它们旨在(除其余以外)使得可以建立有效的离线体验,拦截网络请求并基于网络是否可用以及更新的资源是否驻留在服务器上来采起适当的动做。

(图片来源:https://www.pavlompas.com/blog/web-workers-vs-service-workers-vs-worklets)

Service workers 的浏览器支持状况以下:

因为 Service workers 不是本文的重点,这里阿宝哥就不展开介绍了,感兴趣的小伙伴请自行了解一下。下面咱们开始介绍 Web Workers API。

5、Web Workers API

Worker() 构造函数建立一个 Worker 对象,该对象执行指定的URL脚本。这个脚本必须遵照同源策略 。若是违反同源策略,则会抛出一个 SECURITY_ERR 类型的 DOMException。

5.1 Worker 构造函数

Worker 构造函数的语法为:

const myWorker = new Worker(aURL, options);
复制代码

相关的参数说明以下:

  • aURL:是一个 DOMString 表示 worker 将执行的脚本的 URL。它必须遵照同源策略。
  • options(可选):包含可在建立对象实例时设置的选项属性的对象。可用属性以下:
    • type:用以指定 Worker 类型的 DOMString 值. 该值能够是 classic 或 module。若是未指定,将使用默认值 classic。
    • credentials:用以指定 worker 凭证的 DOMString 值。该值能够是 omit,same-origin 或 include。若是未指定,或者 type 是 classic,将使用默认值 omit (不要求凭证)。
    • name:在 DedicatedWorkerGlobalScope 的状况下,用来表示 Worker 的 scope 的一个 DOMString 值,主要用于调试目的。

须要注意的是,在建立 Web Worker 的时候,可能会出现如下异常:

  • 当 document 不被容许启动 worker 的时候,将抛出一个 SecurityError 异常。好比:若是提供的 aURL 有语法错误,或者与同源策略相冲突(跨域访问)。
  • 若是 worker 的 MIME 类型不正确,将抛出一个 NetworkError 异常。worker 的 MIME 类型必须是 text/javascript
  • 若是 aURL 没法被解析(格式错误),将抛出一个 SyntaxError 异常。

示例

const worker = new Worker("task.js");
复制代码

当咱们调用 Worker 构造函数后会返回一个 Worker 线程对象,用来供主线程操做 Worker。Worker 线程对象的属性和方法以下:

  • Worker.onerror:指定 error 事件的监听函数。
  • Worker.onmessage:指定 message 事件的监听函数,发送过来的数据在 Event.data 属性中。
  • Worker.onmessageerror:指定 messageerror 事件的监听函数。发送的数据没法序列化成字符串时,会触发这个事件。
  • Worker.postMessage():向 Worker 线程发送消息。
  • Worker.terminate():当即终止 Worker 线程。

5.2 Dedicated Worker 示例

下面咱们再来举一个 Dedicated Worker 的例子:

index.html

<!DOCTYPE html>
<html lang="zh-CN">  <head>  <meta charset="UTF-8" />  <meta name="viewport" content="width=device-width, initial-scale=1.0" />  <title>Dedicated Worker Demo</title>  </head>  <body>  <h3>Dedicated Worker Demo</h3>  <script>  const worker = new Worker("task.js");   worker.postMessage({  id: 666,  msg: "Hello Semlinker",  });   worker.onmessage = function (message) {  let data = message.data;  console.log(`Main: Message from worker ${JSON.stringify(data)}`);  worker.terminate();  };   worker.onerror = function (error) {  console.log(error.filename, error.lineno, error.message);  };  </script>  </body> </html>  复制代码

task.js

而 Dedicated Worker 所执行的代码以下所示:

onmessage = function (message) {
 let data = message.data;  console.log(`Worker: Message from main thread ${JSON.stringify(data)}`);  data.msg = "Hi from task.js";  postMessage(data); }; 复制代码

以上代码成功运行后,控制台会输出如下结果:

Worker: Message from main thread {"id": 666,"msg": "Hello Semlinker"}
worker-demo.html:20 Main: Message from worker {"id":666, "msg":"Hi from task.js"} 复制代码

为了让你们更好的理解 Web Worker 的工做流程,咱们来了解一下 WebKit 加载并执行 Worker 线程的流程:

(图片来源:http://www.alloyteam.com/2015/11/deep-in-web-worker/)

5.3 观察 Dedicated Worker

看到这里相信有些小伙伴会好奇,介绍了那么多 Web Worker 的相关知识,在哪里能够直观地感觉到 Web Worker,接下来咱们将从如下两个角度来观察它。

5.3.1 开发者工具

这里阿宝哥以 Chrome 浏览器为例,首先打开 Chrome 开发者工具,而后选择 Sources -> Page

5.3.2 Chrome 任务管理器 & 活动监视器

打开 Chrome 任务管理器以后,咱们能够找到当前 Tab 页对应的进程 ID,即为 5194,接着咱们打开 macOS 下的活动监视器,而后选中 5194 进程,而后对该进程进行取样操做:

取样完成后,能够看到当前渲染进程中完整的线程信息,红框中标出的就是咱们想要找的 Dedicated Worker

原本是想一口气写完 “你不知道的 Web Workers”,但考虑到部分小伙伴们的感觉,避免出现如下群友提到的状况,阿宝哥决定拆成上下两篇。

下篇阿宝哥将着重介绍 Web Worker 一些常见的使用场景和 Deno Web Workers 的相关实现,感兴趣的小伙们记得持续关注阿宝哥哟。

阅读其余 “你不知道的 XXX 系列教程”

6、参考资源

建立了一个 “全栈修仙之路交流群” 的微信群,想加群的小伙伴,加我微信 "semlinker",备注 2。阿里、京东、腾讯的大佬都在群里等你哟。 semlinker/awesome-typescript 1.6K

本文使用 mdnice 排版