原文地址:https://blog.sessionstack.com/how-javascript-works-the-building-blocks-of-web-workers-5-cases-when-you-should-use-them-a547c0757f6a

How JavaScript works: The building blocks of Web Workers + 5 cases when you should use them

JavaScript的工作原理:Web Workers的构建块+当您应该使用它们时的5个案例

您应该已经熟悉JavaScript在单个线程上运行的事实,正如我们之前非常详细地讨论过的那样。但是,JavaScript为开发人员提供了编写异步代码的机会。

异步编程的局限性

异步编程使您的应用程序UI能够及时响应,通过“调度”部分代码在事件循环中稍后执行,从而允许首先执行UI呈现。

异步编程的一个很好的用例就是发出AJAX请求。由于请求可能需要花费大量时间,因此可以异步进行,并且在客户端等待响应时,可以执行其他代码。

// This is assuming that you're using jQuery
jQuery.ajax({
url: 'https://api.example.com/endpoint',
success: function(response) {
// Code to be executed when a response arrives.
}
});

但是,这会产生一个问题 - 请求由浏览器的WEB API处理,但其他代码如何异步?例如,如果成功回调内部的代码非常占用CPU,那该怎么办:

var result = performCPUIntensiveCalculation();

如果performCPUIntensiveCalculation不是HTTP请求而是阻塞代码(例如巨大的for循环),则无法释放事件循环并取消阻止浏览器的UI - 它将冻结并对用户无响应。

这意味着异步函数只解决了JavaScript语言的一小部分单线程限制。

在某些情况下,使用setTimeout可以在长时间运行的计算中取消阻止UI,从而获得良好的效果。例如,通过在单独的setTimeout调用中对复杂计算进行批处理,您可以将它们放在事件循环中的不同“位置”上,这样就可以花时间来执行UI呈现/响应。

我们来看一个计算数值数组平均值的简单函数:

function average(numbers) {
var len = numbers.length,
sum = 0,
i; if (len === 0) {
return 0;
} for (i = 0; i < len; i++) {
sum += numbers[i];
} return sum / len;
}

这就是你如何重写上面的代码并“模拟”异步性:

function averageAsync(numbers, callback) {
var len = numbers.length,
sum = 0; if (len === 0) {
return 0;
} function calculateSumAsync(i) {
if (i < len) {
// Put the next function call on the event loop.
setTimeout(function() {
sum += numbers[i];
calculateSumAsync(i + 1);
}, 0);
} else {
// The end of the array is reached so we're invoking the callback.
callback(sum / len);
}
} calculateSumAsync(0);
}

这将使用setTimeout函数,该函数将在事件循环中进一步添加计算的每个步骤。在每次计算之间,将有足够的时间进行其他计算,这是解冻浏览器所必需的。

Web Workers将拯救你

HTML5为我们带来了许多开箱即用的好东西,包括:

  • SSE
  • Geolocation
  • Application cache
  • Local Storage
  • Drag and Drop
  • Web Workers

Web Workers是浏览器中的线程,可用于执行JavaScript代码而不会阻止事件循环。

这真是太神奇了。 JavaScript的整个范例都是基于单线程环境的思想,但Web Workers可以删除(部分)这种限制。

Web Workers允许开发人员在后台运行长时间运行且计算密集的任务,而不会阻止UI,从而使您的应用程序更具响应性。更重要的是,为了破解事件循环的方式,不需要使用setTimeout的技巧。

这是一个简单的演示,显示了使用和不使用Web Workers对数组进行排序的区别。

Web Worker概述

Web Workers允许您执行一些操作,例如启动长时间运行的脚本来处理计算密集型任务,但不会阻止UI。实际上,这一切都是并行发生的。 Web Workers是真正的多线程。

您可能会说 - “JavaScript不是单线程语言吗?”。

当你意识到JavaScript是一种没有定义线程模型的语言时,这应该是你的“啊哈!”时刻。 Web Workers不是JavaScript的一部分,它们是可以通过JavaScript访问的浏览器功能。大多数浏览器历来都是单线程的(当然,这已经改变了),并且大多数JavaScript实现都发生在浏览器中。 Web Worker没有在Node.JS中实现 - 它有一个“cluster”或“child_process”的概念,它有点不同。

值得注意的是,该规范提到了三种类型的Web Worker:

  • Dedicated Workers
  • Shared Workers
  • Service workers

Dedicated Workers(专用Workers)

专用Web Worker由主进程实例化,只能与之通信。

Shared Workers(共享Workers)

在同一来源(不同的浏览器选项卡,iframe或其他共享工作者)上运行的所有进程都可以访问共享工作者。

Service Workers(服务Workers)

服务工作者是针对原点和路径注册的事件驱动的工作者。它可以控制与之关联的网页/网站,拦截和修改导航和资源请求,以及以非常精细的方式缓存资源,让您可以很好地控制应用在特定情况下的行为(例如,当网络不是可用。)

在这篇文章中,我们将专注于“专用Workers”,并将他们称为“Web Workers”或“Workers”。

Web Worker是如何工作的

Web Workers是以.js的文件形式来呈现的,这些文件通过页面中的异步HTTP请求被引进来。 Web Worker API完全隐藏了这些请求。

Workers利用类似线程的消息传递来实现并行性。它们非常适合用户保持UI最新,高性能和响应性。

Web Workers在浏览器中的独立线程中运行。因此,它们执行的代码需要包含在单独的文件中。记住这一点非常重要。

让我们看看如何创建基本的Worker:

var worker = new Worker('task.js');

如果“task.js”文件存在且可访问,则浏览器将生成一个新线程,该线程异步下载该文件。下载完成后,它将立即执行,worker将开始。
如果提供的文件路径返回404,则工作程序将以静默方式失败。

要启动创建的worker,需要调用postMessage方法:

worker.postMessage();

Web Worker通信

为了在Web Worker和创建它的页面之间进行通信,您需要使用postMessage方法或广播通道。

postMessage方法

较新的浏览器支持JSON对象作为方法的第一个参数,而较旧的浏览器仅支持字符串。

让我们看一个示例,通过将JSON对象作为一个更“复杂”的示例传递,创建工作者的页面如何与之来回通信。传递一个字符串是完全一样的。

让我们看看下面的HTML页面(或者更精确的部分):

<button onclick="startComputation()">Start computation</button>

<script>
function startComputation() {
worker.postMessage({'cmd': 'average', 'data': [1, 2, 3, 4]});
}
var worker = new Worker('doWork.js');
worker.addEventListener('message', function(e) {
console.log(e.data);
}, false); </script>

这就是我们的Worker脚本:

self.addEventListener('message', function(e) {
var data = e.data;
switch (data.cmd) {
case 'average':
var result = calculateAverage(data); // Some function that calculates the average from the numeric array.
self.postMessage(result);
break;
default:
self.postMessage('Unknown command');
}
}, false);

单击该按钮时,将从主页面调用postMessage。 worker.postMessage行将JSON对象传递给worker,添加cmd和数据键及其各自的值。 worker将通过定义的消息处理程序处理该消息。

当消息到达时,实际计算正在worker中执行,而不会阻止事件循环。worker正在检查传递的事件e并像标准JavaScript函数一样执行。完成后,结果将传递回主页面。

在worker的上下文中,self和this都引用了worker的全局范围。

有两种方法可以停止worker:通过从主进程中调用worker.terminate()或通过调用worker本身内部的self.close()。

Broadcast Channel

广播频道是一种更通用的通信API。它允许我们向共享相同来源的所有上下文广播消息。从同一来源提供的所有浏览器标签,iframe或worker都可以发送和接收消息:

// Connection to a broadcast channel
var bc = new BroadcastChannel('test_channel'); // Example of sending of a simple message
bc.postMessage('This is a test message.'); // Example of a simple event handler that only
// logs the message to the console
bc.onmessage = function (e) {
console.log(e.data);
} // Disconnect the channel
bc.close()

在视觉上,您可以看到广播频道的外观更清晰:

广播频道的浏览器支持有限:

消息的大小

有两种方法可以向Web Workers发送消息:

  • 复制消息:消息被序列化,复制,发送,然后在另一端反序列化。页面和worker不共享同一个实例,因此最终结果是每次传递都会创建一个副本。大多数浏览器通过自动JSON编码/解码任一端的值来实现此功能。正如所料,这些数据操作为消息传输增加了大量开销。消息越大,发送的时间越长。
  • 转移邮件:这意味着原始发件人一旦发送就无法再使用它。传输数据几乎是即时的。限制是只有ArrayBuffer可以转移。

Web Workers可用的功能

Web Workers由于具有多线程特性,因此只能访问JavaScript功能的子集。以下是功能列表:

  • The navigator object
  • The location object (read-only)
  • XMLHttpRequest
  • setTimeout()/clearTimeout() and setInterval()/clearInterval()
  • The Application Cache
  • Importing external scripts using importScripts()
  • Creating other web workers

Web Worker的局限

遗憾的是,Web Workers无法访问一些非常关键的JavaScript功能:

  • The DOM (it’s not thread-safe)
  • The window object
  • The document object
  • The parent object

这意味着Web Worker无法操纵DOM(以及UI)。它有时会很棘手,但是一旦你学会了如何正确使用Web Workers,你就会开始将它们作为单独的“计算机器”使用,而所有的UI更改都将在你的页面代码中进行。Worker将为您完成所有繁重的工作,一旦完成工作,您将把结果传递给对UI进行必要更改的页面。

处理错误

与任何JavaScript代码一样,您将需要处理Web Workers中引发的任何错误。如果在执行worker时发生错误,则会触发ErrorEvent。该界面包含三个有用的属性,用于确定出现了什么问题:

  • filename - 导致错误的工作程序脚本的名称
  • lineno - 发生错误的行号
  • message - 错误的描述

以下是示例:

function onError(e) {
console.log('Line: ' + e.lineno);
console.log('In: ' + e.filename);
console.log('Message: ' + e.message);
} var worker = new Worker('workerWithError.js');
worker.addEventListener('error', onError, false);
worker.postMessage(); // Start worker without a message.
self.addEventListener('message', function(e) {
postMessage(x * 2); // Intentional error. 'x' is not defined.
};

在这里,您可以看到我们创建了一个worker并开始侦听错误事件。

在worker内部(在workerWithError.js中),我们通过将x乘以2来创建故意异常,而x未在该范围中定义。异常传播到初始脚本,并且正在调用onError以及有关错误的信息。

Web Worker的好用例

到目前为止,我们已经列出了Web Workers的优势和局限性。现在让我们看看它们最强大的用例是什么:

  • 光线跟踪:光线跟踪是一种渲染技术,用于通过将光线路径跟踪为像素来生成图像。光线跟踪使用非常耗费CPU的数学计算来模拟光的路径。这个想法是模拟一些效果,如反射,折射,材料等。所有这些计算逻辑都可以添加到Web Worker中,以避免阻塞UI线程。更好的是 - 您可以轻松地在几个工作者(以及几个CPU之间)之间分割图像渲染。以下是使用Web Workers进行光线跟踪的简单演示 - https://nerget.com/rayjs-mt/rayjs.html。
  • 加密:由于对个人和敏感数据的监管越来越严格,端到端加密越来越受欢迎。加密可能是非常耗时的事情,特别是如果有大量数据必须经常加密(例如,在将其发送到服务器之前)。这是一个非常好的场景,可以使用Web Worker,因为它不需要任何访问DOM或任何花哨的东西 - 它是纯粹的算法来完成它们的工作。一旦进入工作人员,它对最终用户是无缝的,并且不会影响他们的体验。
  • 预取数据:为了优化您的网站或Web应用程序并缩短数据加载时间,您可以利用Web Workers提前加载和存储一些数据,以便以后在需要时使用它。在这种情况下,Web Workers非常棒,因为它们不会影响应用程序的UI,这与没有工作人员的情况不同。
  • 渐进式Web应用程序:即使网络连接不稳定,也必须快速加载。这意味着数据必须本地存储在浏览器中。这是IndexDB或类似API发挥作用的地方。基本上,需要客户端存储。为了在不阻塞UI线程的情况下使用,必须在Web Workers中完成工作。好吧,在IndexDB的情况下,有一个异步API,即使没有工作人员也允许你这样做,但之前有一个同步API(可能会再次引入),它只能在worker中使用。
  • 拼写检查:基本的拼写检查工具按以下方式工作 - 程序读取带有正确拼写单词列表的字典文件。该字典被解析为搜索树,以使实际文本搜索有效。当向检查器提供单词时,程序检查它是否存在于预构建的搜索树中。如果在树中找不到该单词,则可以通过替换替换字符来为用户提供替代拼写,并测试它是否是有效单词 - 如果它是用户想要写的单词。所有这些处理都可以轻松卸载到Web Worker,这样用户只需键入单词和句子而不会阻止UI,而工作人员可以执行所有搜索和提供建议。

—— 完 ——

												

[翻译]Review——How JavaScript works:The building blocks of Web Workers的更多相关文章

  1. JavaScript是如何工作的:Web Workers的构建块 + 5个使用他们的场景

    摘要: 理解Web Workers. 原文:JavaScript是如何工作的:Web Workers的构建块 + 5个使用他们的场景 作者:前端小智 Fundebug经授权转载,版权归原作者所有. 这 ...

  2. 企业架构研究总结(35)——TOGAF架构内容框架之构建块(Building Blocks)

    之前忙于搬家移居,无暇顾及博客,今天终于得闲继续我的“政治课”了,希望之后至少能够补完TOGAF方面的内容.从前面文章可以看出,笔者并无太多能力和机会对TOGAF进行理论和实际的联系,仅可对标准的文本 ...

  3. TOGAF架构内容框架之构建块(Building Blocks)

    TOGAF架构内容框架之构建块(Building Blocks) 之前忙于搬家移居,无暇顾及博客,今天终于得闲继续我的“政治课”了,希望之后至少能够补完TOGAF方面的内容.从前面文章可以看出,笔者并 ...

  4. Intel® Threading Building Blocks (Intel® TBB) Developer Guide 中文 Parallelizing Data Flow and Dependence Graphs并行化data flow和依赖图

    https://www.threadingbuildingblocks.org/docs/help/index.htm Parallelizing Data Flow and Dependency G ...

  5. bc.34.B.Building Blocks(贪心)

    Building Blocks Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) ...

  6. DTD - XML Building Blocks

    The main building blocks of both XML and HTML documents are elements. The Building Blocks of XML Doc ...

  7. HDU—— 5159 Building Blocks

    Problem Description After enjoying the movie,LeLe went home alone. LeLe decided to build blocks. LeL ...

  8. [书籍翻译] 《JavaScript并发编程》第五章 使用Web Workers

    本文是我翻译<JavaScript Concurrency>书籍的第五章 使用Web Workers,该书主要以Promises.Generator.Web workers等技术来讲解Ja ...

  9. [技术翻译]在现代JavaScript中编写异步任务

    本周再来翻译一些技术文章,本次预计翻译三篇文章如下: 04.[译]使用Nuxt生成静态网站(Generate Static Websites with Nuxt) 05.[译]Web网页内容是如何影响 ...

随机推荐

  1. 高可用群集HA介绍与LVS+keepalived高可用群集

    一.Keepalived介绍 通常使用keepalived技术配合LVS对director和存储进行双机热备,防止单点故障,keepalived专为LVS和HA设计的一款健康检查工具,但演变为后来不仅 ...

  2. tcping测试端口是否畅通

    https://elifulkerson.com/projects/tcping.php 下载tcping.exe 执行exec文件或者放到C:\Window目录下执行 tcping IP 端口

  3. 人工鱼群算法超详细解析附带JAVA代码

    01 前言 本着学习的心态,还是想把这个算法写一写,给大家科普一下的吧. 02 人工鱼群算法 2.1 定义 人工鱼群算法为山东大学副教授李晓磊2002年从鱼找寻食物的现象中表现的种种移动寻觅特点中得到 ...

  4. 39.oracle高级篇

    标题说是高级篇,其实也就是相对于基础篇来说的,也不是很深奥,自己平时工作中也都会用到,这里回忆的并不是特别冷门的知识,不要掉以轻心,以为“高级”就觉得工作中不会用到了. 一.select into 和 ...

  5. 网络基础 08_NAT

    1 NAT的基本概念 为什么需要NAT IPv4地址紧缺 什么是NAT NAT(Network Address Translation) 私有IPv4地址 10.0.0.0 - 10.255.255. ...

  6. Zynq-7000 FreeRTOS(二)中断:Timer中断

    总结Zynq-7000 这款器件中的Timer定时器中断,为FreeRTOS中断做准备.在 ZYNQ 的纯 PS 里实现私有定时器中断. 每隔一秒中断一次, 在中断函数里计数加 1, 通过串口打印输出 ...

  7. 同一个Activity先后加载2个Layout,从layout1取值传入layout2

    同一个Activity先后加载2个Layout,从layout1取值传入layout2 没啥技术含量,就权当丰富下mono for android的小代码. Main.xaml <?xml ve ...

  8. VS生成Map文件

    一.右键项目属性->链接器->启用增量链接:关闭,选择  否 (/INCREMENTAL:NO) 二.右键项目属性->链接器->调试-> 生成调试信息:是 (/DEBUG ...

  9. Couchbase进阶-集群与版本升级

    最近在负责公司Couchbase版本升级工作,之前只有一台Cache服务器,使用Couchbase Enterprise Edition 1.8,为避免单点故障现在需要新增加一台Cache服务器做负载 ...

  10. UI的线程问题:单线程原因及更新UI的四种方式

    1.UI线程为什么设计为单线程? UI控件的操作不是线程安全的,对于多线程并发访问的时候,如果使用加锁机制会导致: UI控件的操作变得很复杂. 加锁的操作必定会导致效率下降. 所以android系统在 ...