web worker

Web workers 提供了一种在浏览器中单线程运行 js 代码的方法。单线程处理请求显示内容以及通过键盘、鼠标点击,和其他设备产生的用户交互, 以及对 AJAX 请求的响应。事件处理和AJAX请求虽然是异步的,但是它们本质仍然在单线程中运行,必须要尽可能的快去完成。否则,浏览器中的就会停止响应,直到任务处理完成。

Web workers 允许 js 代码在单独的线程中运行,完全独立于浏览器线程及其通常的活动。

今年来关于对 Web workers 的使用有很多的争论,这几年cpu的运算速度是非常快的,几乎所有的个人电脑都有几个G的内存。同样,移动设备已经越来越接近台式机cpu速度和的内存大小。

曾经被认为是计算密集型的应用现在被认为不是那么糟糕了。

然后真实的情况却是

但是很多时候,我们只考虑在开发环境中测试的一个应用程序的执行。而在用户侧,可能同时会进行多个应用。

因此,在隔离状态下运行的应用程序可能不需要使用Web workers,但是有必要使用它们为各种用户提供最佳体验。

一下代码演示了如何创建一个 Web workers

1
new Worker('my-worker.js')

一旦创建了 web worker,它就在独立于主浏览器线程的单独线程中运行,执行脚本中给定给它的任何代码。

在worker和js主线程之间传递数据:

  • 发送端上的postMessage()函数
  • 接收端上的消息事件处理程序

消息事件处理程序接收事件参数,与其他事件处理程序一样;此事件有一个“data”属性,其中包含从另一端传递过来的任何数据。

1
2
3
4
5
6
7
8
9
var worker = new Worker("demo1-hello-world.js");

// Receive messages from postMessage() calls in the Worker
worker.onmessage = (evt) => {
console.log("Message posted from webworker: " + evt.data);
}

// Pass data to the WebWorker
worker.postMessage({data: "123456789"});
1
2
3
4
5
// demo1-hello-world.js
postMessage('Worker running');
onmessage = (evt) => {
postMessage("Worker received data: " + JSON.stringify(evt.data));
};

上面代码的输出结果:

1
2
Message posted from webworker: Worker running
Message posted from webworker: Worker received data: {“data”:”123456789"}

worker是常驻进程存在的

在一个 worker 的生命周期中,可以在浏览器和 worker 之间发送和接收多个消息。

web workers以两种方式确保代码安全、无冲突的执行:

  • 工作线程的独立、隔离的全局环境,独立于浏览器环境
  • 使用postMessage()在主线程和工作线程之间进行消息传递

每个 worker 线程都有一个独立的全局环境,该环境与浏览器页面的 js 环境不同。worker 线程根本不能访问页面的 js 环境中的任何东西——DOMwindowdocument 对象都不行。

此外,通过 postMessage() 传递的任何数据在传递之前都会被复制,因此更改主线程中的数据不会导致 worker 线程中的数据发生更改。这提供了固有的保护,避免在主线程和 worker 线程之间传递的数据发生冲突的并发更改。

web worker的典型应用场景

典型应用:执行运算需要消耗大量的CPU时间或采取一个不可预知的时间来访问数据。

举例说明:

  • 预取或缓存数据供以后使用
  • 轮询和处理来自web服务的数据
  • 大数据集的处理和显示
  • 游戏中与移动相关的计算
  • 图像处理和过滤
  • 处理文本数据(代码语法、拼写检查、字数)

CPU时间是最简单的使用,但是对网络资源的请求也非常重要。

很多时候,internet上的网络通信可以在几毫秒内执行,但有时网络资源变得不可用,直到网络恢复或请求超时才会停止(这可能需要1-2分钟才能清除)。

而且,有些代码在开发环境中单独测试时可能不需要很长时间就可以运行,但当多个应用同时运行时,它可能成为在用户环境中运行的问题。

分享几个实际案例

最终的想法

针对浏览器的兼容判断,可以通过一个简单的判断 if (typeof Worker !== "undefined") 来创建和保护的我们的 web worker, 在 web worker 外部执行相同的代码(例如:setTimeout或requestAnimationFrame)