likes
comments
collection
share

JavaScript 周报 436 期之 WebWorker 是什么

作者站长头像
站长
· 阅读数 2

本周 JavaScript 436期周报链接。这里面主要我想谈谈 WebWorker 相关的内容。

众所周知,JavaScript 使用运行在单线程上的。但是 JavaScript 可以处理异步代码,其中 Ajax 就是个很好的例子。异步带来的用户体验不必多说,但是这里有个问题:如果异步之后的成功回调是一次密集 CPU 操作。那么本来因为异步而产生的非阻塞用户体验,就又会因为无法从事件循环出解脱而又产生阻塞。对用户而言便又产生了不响应的 UI。这种情况,我们可以认为 JavaScript 只是解决了单线程的部分限制。可以假设,如果我们把这一次密集 CPU 操作也在异步中执行,那么用户体验仍然一如既往地流畅。

Web Worker 就应用而生了。

Web Workers 概述

Web Worker 是真正的多线程。

Web Worker并不会阻塞事件循环。参考这个 demo 可以看到在 5 万条数据排序的时候,使用 WebWorker 带来的体验差别。Web Worker 并不是 JavaScript 的一部分,它是通过 JavaScript 可以访问的浏览器特性。然而,Web Worker 并没有在 Node.js 中实现,有点像子进程的概念,但是却有不同。

Web Worker是有三种类型,在 MDN 中有详细定义:

  • 专用 Workers
  • 共享 Workers
  • 服务 Workers

其中,专用 Workers 是通过主进程实例化,也只能通过主进程通信;共享 Workers 可以访问所有同源的进程(在不同的浏览器标签,窗口或者其他的共享 Workers);服务 Workers 是针对源和路径的事件驱动 worker,用在网络不可用的情况下,可以控制网站和相关站点,插入和修改导航和资源请求,缓存资源等。

如何工作

Web Workers 在浏览器中运行一个独立的线程。正因如此,执行的代码需要被包含在一个独立的文件中,这一点比较重要。使用方式也很简单:

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

浏览器会创建一个异步下载的文件线程。当下载完成后,会被执行。通过调用 postMessage 方法来使用创建好的 worker。它可以让一个 Web Worker 和页面之间通信。

如何使用 postMessage 方法

比较新的浏览器支持 JSON 作为第一个参数,而旧的浏览器只支持字符串。

<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>

在 new 一个 Worker 之后,给它的实例注册一个叫 message 的监听事件。同时在我们的 doWork.js 里,也要注册相同事件用来处理数据。

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);

当消息到达的时候,worker 就开始执行计算,具体来说运行 calulateAverage 方法。结束之后,把结果传递给主页面。在 worker 的上下文环境中,selfthis 都是 worker 的全局,与 window 无关。有两种方式可以结束 worker: worker.terminate()self.close()

Web Worker 可用特性

  • navigator 对象
  • location 对象(只读)
  • XMLHttpRequest
  • setTimeout()/clearTimeout()setInterval()/clearInterval()
  • 应用缓存
  • 使用 importScripts() 导入外部脚本
  • 创建其他的 web workers

Web Worker 限制

  • DOM(很显然,多线程的操作DOM是不合理和不安全的)
  • window 对象
  • document 对象
  • parent 对象

几个 Web Workers 的场景

  • 光线追踪

    为了模拟光线路径,这种场景是需要大量计算的,但是不能再每次大量计算的时候就让光线变得卡顿或者不自然,这时候workers 就可以发挥作用了。

  • 加密

    也是纯粹的计算工作,交给 web workers 正当其用。而且有些加密解密的操作是相当消耗时间的。

  • 预加载数据 当网络不是很稳定的时候,可以先把数据取出来存在本地浏览器缓存中,这样在需要的时候就会减少延迟感

  • 拼写检查

    如果对应的检查数据是一本字典的话。这种场景下,使用 web worker 就十分必要了。

总结一下使用 Web Workers 的场景的共同点:

  1. 延迟甚至不需要 DOM 操作的情况
  2. 短时间使用产生大量计算,会阻塞 UI 线程,导致卡顿的场景
  3. 预处理,异步处理的部分场景

小结

Web Worker 是个浏览器实现的特性,尽管如此,我们还是能够在某些地方发挥它的优势去增强用户体验,遵循“渐进增强,平稳退化”得原则。没有理由去拒绝使用它。但其实,Web Worker 的使用场景也十分具有特点,它应该不是作为解决卡顿问题的首选,因为在前端,除了动画以外往往没有特别大的计算量。大多数的不流畅用户体验,多半是重绘和重排没有优化好而引起的,千万不可缘木求鱼,为了 Web Worker 什么都往上鼓捣。

参考资料

  1. blog.sessionstack.com/how-javascr…

JavaScript 周报 436 期之 WebWorker 是什么