本篇目录:

  • 使用缘由
  • Web Worker
  • 使用Web Worker
    • 支持性检测
    • 创建worker.js
    • 创建Worker对象
    • 消息处理
    • 错误处理
    • 终止Web Worker
  • 使用后记

效果示意

圣诞节为集团活动制作了一款竞速(戳手指)类的H5互动小游戏,在这个的开发过程中第一次体验了Web Worker的功能,感觉还是不错的,整理分享一下。

使用缘由

由于这次制作的H5互动小游戏需要针对点击速度进行动效的更新,然后游戏场景中有很多的元素,在使用canvas的过程中,发现在安卓机上面会出现快速点击之后页面卡顿的现象,由于动画的卡顿,导致页面上面的计时器(setInterval)被卡停了,最终出现了安卓机的游戏结果拉了IOS一条街,这不科学啊。

本次H5游戏的相关处理不做主要内容,可能会是由于自己处理优化不够导致的问题,请大家勿深究。

分析原因,应该是页面的动画频繁渲染,导致计时器处理事件被阻塞了,这也是JavaScript处理是单线程的一个直接结果。所以就想到了Web Worker是否可以解决我的问题,来处理计时器的计算呢?

JavaScript 语言采用的是单线程模型,也就是说,所有任务只能在一个线程上完成,一次只能做一件事。前面的任务没做完,后面的任务只能等着。

Web Worker

当在 HTML 页面中执行脚本时,页面的状态是不可响应的,直到脚本已完成。

Web Worker 是运行在后台的 JavaScript,独立于其他脚本,不会影响页面的性能。
您可以继续做任何愿意做的事情:点击、选取内容等等,而此时 Web Worker 在后台运行。

Web Worker的基本原理就是在当前JavaScript的主线程中,使用Worker类加载一个JavaScript文件来开辟一个新的线程,起到互不阻塞执行的效果,并且提供主线程和新线程之间数据交换的接口:postMessageonmessage
所以你可以在前台做一些小规模分布式计算之类的工作,不过Web Worker有以下一些使用限制:

  • Web Worker无法访问DOM节点;
  • Web Worker无法访问全局变量或是全局函数;
  • Web Worker无法调用alert()或者confirm之类的函数;
  • Web Worker无法访问window、document之类的浏览器全局变量;

使用Web Worker

支持性检测

1
2
3
4
5
if(typeof(Worker)!=="undefined") {
alert('支持worker')
} else {
alert('不支持worker')
}

创建worker.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
var self =this;

self.addEventListener('message', function (e) {
var data = e.data;
switch (data.cmd) {
case 'start':
startTimer();
break;
case 'stop':
stopTimer();
break;
default:
break;
};
}, false);

var timerId = null, gameTime = 0;

var startTimer = function () {
timerId = setInterval(function () {
gameTime += 16;
var million = String(gameTime % 1000).substr(0, 2);
var second = String(Math.floor(gameTime / 1000));
second = second.length >= 2 ? second : '0' + second;
self.postMessage({
second: second,
million: million
});
}, 16);
}

var stopTimer = function () {
clearInterval(timerId);
gameTime = 0;
}

以上代码中重要的部分是 postMessage() 方法 - 它用于向 HTML 页面传回一段消息。当然,我的应用场景太简单了,web worker 通常不用于如此简单的脚本,而是用于更耗费 CPU 资源的任务。

创建Worker对象

1
2
3
4
5
if(typeof(Worker)!=="undefined") {
let worker = new Worker("./worker.js");
} else {
alert('不支持worker')
}

消息处理

1
2
3
worker.onmessage = function (event) {
// 接收到worker计算相关的数据
}

当 web worker 传递消息时,会执行事件监听器中的代码。event.data 中存有来自 event.data 的数据。

错误处理

1
2
3
worker.onerror(function (event) {
// 错误处理
});

终止Web Worker

1
worker.terminate();

使用后记

在使用Web Worker之后,新开一个线程用于计时器的计算,从而基本解决了游戏时间的问题。由于计时器的间隔时间和发送消息的过程,可能还是和实际的间隔时间会有一定的出入,但是从活动来说已经在接受范围内了。

通过这次简单的使用Web Worker,初步理解了其基本原理和使用方法,也为以后的相似情景找到了解决的路径,希望能够对遇到同样问题的朋友有所帮助。