Web Workers

介绍

关于 Web Worker 介绍以及简单的使用,可以查看 使用 Web Workers 这篇文章。

在此之前,最好对 JS 的运行机制有一点点的了解,可以参照 浅谈js运行机制(线程)

因为 JS 线程牵扯到 DOM 的创建,更新等操作,所以 JS 线程和浏览器的 UI 线程互斥的,这也就意味着当执行 JS 代码时,UI 将无法为用户提供交互。

在网页开发中,要尽量避免 JS 执行占用太多的时间,经统计,这个时间最好不要超过 100ms,也就是说,在 100msjs 线程必须要结束并将浏览器控制权交给 UI 线程。至于为什么是 100ms,在 《高性能 JavaScript》 一书中也给出了解释,大概的意思就是一旦超过 100ms 网站的用户就会感觉他们对网页的操作失去了控制。

如果你的操作时间已经大于了 100ms,你就应该考虑是否是代码出现了问题,如果不是代码本身的问题,那么可以考虑使用代码分块,延迟加载等技术改善 JS 代码运行时间。

当然,如果你的代码的的确确是正常的,而且已经优化的不能再优化了,这个时候就可以考虑使用 Worker 了。由于 Worker 的运行线程并不在 js 主线程上,所以在 worker 的运行期间,UI 线程仍然可以正常响应用户的操作。

其实,Worker 又分专用和共享这两种,故名思意,专用就是由创建它的脚本文件独自使用,而共享则由许多脚本文件共享使用。不过就目前而言,专用 Worker 的浏览器兼容性已经非常好了,而共享 Worker 目前还存在很多问题,所以暂时不介绍。

Web Worker 兼容性查看


基本语法

在使用之前,先检验当前浏览器是否支持 Worker

对于创建 Worker 的脚本而言:

  1. 首先使用 new Worker('worker.js') 创建 Worker
  2. 其次使用 worker.onmessage 监听消息事件,如果 worker 完成了任务,将信息发送过来的时候会触发该事件,利用 event.data 可以将数据提取出来。
  3. 利用 worker.postMessage(msg) 可以向 worker 发送数据,一般用于告诉 worker 可以开始工作了或传递参数。
  4. 利用 worker.terminate() 可以终止 worker 的执行。

对于 worker.js 脚本而言:

  1. 存在一个 self 变量,指向自身。
  2. 利用 self.onmessage 监听是否接收到数据,利用 event.data 可以提取数据。
  3. 利用 postMessage(msg) 向创建脚本发送执行结果。
  4. 可以利用 close() 关闭自身。
  5. 当然,还可以利用 new Worker() 继续创建 worker

使用

在使用之前,我们首先需要用 node express 搭建一个后台环境,其实也很简单,首先利用 npm i express --save-dev 命令安装 express 框架,然后新创一个 app.js 的脚本文件,内容如下:

然后运行 node app.js 即可正常访问到 home.html,在此文件中,我们就可以创建 worker 并且按照上面介绍的语法使用了。

如果我们需要在网站中进行数据的排序,当数据比较多的时候,即是是使用快速排序,也需要花费不少的时间,这个时候我们就可以使用 worker 做这种脏活累活。

home.html 中添加如下代码

由于只是模拟这种情况,所以并没有在 postMessage() 中将要排序的数组传递进去,获取随机数据数组的任务也交给了 worker。下面来看看 worker 的具体代码:

可见, worker 的任务就是获取一个 400 万长度的随机数组,然后利用快速排序进行排序,这段代码如果在主 js 线程中执行的话,会造成页面 1s 中的卡顿。

由此可知,如果利用好了 worker,不仅可以提高用户的体验,更可以做到以前我们无法做到的事情。

还有一点值得一提的是,worker 中还可以进行 AJAX 请求,这样一来我们又可以将 ajax 写在 worker.js 中了。有人可能要问了, ajax 请求本来不就是异步请求吗?这么说是没有错的,不过有的时候我们还需要对 AJAX 请求返回的数据进行处理,如果这个处理过程很复杂或者需要花费很长时间的话,则需要将其放到 worker 中。如果 AJAX 返回的数据很简单而且不需要做额外的处理,则大可不必使用 worker,因为使用 worker 本身也是有代价的。

下面来看一个使用 AJAX 的例子,首先在 app.js 中添加如下代码:

其次是 worker.js


End!

Add a Comment

电子邮件地址不会被公开。 必填项已用*标注