前言
倒计时我们经常用。之前我也有很多文章提及过。例如:setTimeout倒计时等等。最近在移动端开发过程中,遇到一个ios手机滑动,倒计时卡住的问题,针对这个问题,我们可以用js的Worker。
倒计时案例
用setInterval写的最基本的倒计时,代码如下:
<body>
<div id="haorooms">60</div>
<script>
var haorooms = document.getElementById('haorooms');
var num = 60;
var T = setInterval(function(){
haorooms.innerHTML = --num;
if(num <= 0){
clearInterval(T);
}
}, 1000);
</script>
</body>
这段代码在PC中可以正常运行,在Android中也可以正常运行,但是拿到ios中,就会有一个问题,来看图:
上图中,当倒计时走到37的时候,用手拖动页面,这个时候js代码会被阻塞,导致倒计时不在执行。
针对这个问题,只能用我们上文中提及的Worker API了。
Worker API
Web Workers API 的 Worker 接口代表一个可以轻松创建的后台任务,并可以将消息发送回其创建者。创建一个工作程序只要简单的调用Worker() 构造函数,并指定一个要在工作线程中运行的脚本。
worker 还能够使用 XMLHttpRequest 实现网络 I/O 操作, 只不过 XMLHttpRequest 上的 responseXML 与 channel 两个属性值始终返回 null。
2个方法
1、postMessage()
向 worker 的内部作用域内传递消息。该方法接收一个单独的参数,即要传递给 worker 的数据。
void postMessage( Object aMessage [, sequence<Transferable> transferList]);
参数:
aMessage:
传输给 worker 的对象;它将包含于传递给 onmessage 处理函数的事件对象中的 data 字段内。你可以传递任意值或是经过结构化拷贝算法处理过的 JavaScript 对象,即可以包含循环引用。
transferList:
一个可选的对象数组,用于转让它们的所有权。如果一个对象的所有权被转让,那么它在原来的上下文内将不可使用,而只能在转让到的 worker 内可用。
2、terminate()
立即终止 worker。该方法不会给 worker 留下任何完成操作的机会;就是简单的立即停止。
解决方案
我们的思路是,将倒计时的计算放到一个单独的文件里,使用 Worder 去执行这个文件。
新建一个 countdown.js 文件:
self.onmessage = function(event){
var num = event.data;
var T = setInterval(function(){
self.postMessage(--num);
if(num <= 0){
clearInterval(T);
self.close();
}
}, 1000);
}
由于这个js文件是由 Worker 来在后台执行的文件,所以这个文件内代码的 self 指向的就是 Worker 对象。我们通过 onmessage 时间接收来自页面的倒计时数值,然后原封不动的把之前的倒计时代码拷贝过来,唯一不同的就是使用 self.close() 语句来关闭 Worker。
然后修改之前的页面文件如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>倒计时</title>
</head>
<body>
<div id="haorooms">60</div>
<script>
var haorooms = document.getElementById('haorooms');
var w = new Worker('counter.js');
w.postMessage(60);
w.onmessage = function(event){
haorooms.innerHTML = event.data;
}
</script>
</body>
</html>
在PC中刷新你的页面,可以看到依然正确工作,之后再拿到ios中做之前gif图同样的操作,如下图:
我们可以看到,在55秒的时候开始拖动页面,这个时候倒计时停止了,不过,当我们放手之后,倒计时会立刻恢复到正常应该到达的时刻,而不会产生任何误差和延迟,这样,我们就比较完美的解决了这个问题。
注意
上面的Worker代码必须在localhost等环境下面运行,因为上面提及过,它用到了XMLHttpRequest。
关于Worker更多API,请查看:https://developer.mozilla.org/en-US/docs/Web/API/Worker
中文版可以看:https://developer.mozilla.org/zh-CN/docs/Web/API/Worker
部分资料同事提供,来源已无法考究作者。