使用Web Worker 为 JavaScript 创造多线程环境

 

众所周知,Javascript是运行在单线程环境中,也就是说没有办法同时运行多个脚本,也就是说任务只能在一个线程里完成,一次只能做一件事。前面的任务没有结束,后面的任务就只能等着。举个例子,假设用户触发了一段需要一些时间才能完成Javascript代码,那么页面在这段代码执行完成之前,是没有办法响应用户的其他操作的。我们用实际代码来看一下现象。

我们用JavaScript写一个简单的计时器,代码如下:

<!DOCTYPE html>
<html lang='en'>
	<head>
	<meta charset='UTF-8'>
	<title>计时器</title>
	</head>
	<body>
		<div class="time " ><span id="pastTime">00:00:00</span></div><br>
		<hr>
		<input type="button" id="logIn" value="确认" onclick="toDo()"></div>
		<script>
			var counter = 0;
			setInterval(function () {
				counter++;		
				var m=parseInt(counter/3000);
				var s=parseInt((counter%3000)/50);
				var ms=parseInt(counter%50);
				document.getElementById("pastTime").innerHTML=toDub(m)+":"+toDub(s)+":"+toDub(ms);
			},1000/50);
			//补零
			function toDub(n){
				return n<10?"0"+n:""+n;
			}
			function toDo(){
				if (confirm("继续?")){}
			}
		</script>
	</body>
</html>

运行结果如下:

看起来没有问题,但是如果点一下“确认”按钮,问题出现了,这时候浏览器出现一个弹窗需要点击“确认”或者“取消”,也就是说JavaScript代码停在了这里等待用户做选择,这样,计时就被人为的暂停了下来。

那有没有办法不让计时器的运行被打断呢?答案就是使用Web Worker,将代码交给Web Worker去运行,浏览器会在后台启动一个独立的worker线程来专门负责计时器的运行,因此,页面在等待用户做选择的时间里计时器代码是不受用户操作影响的。

代码如下:

<!DOCTYPE html>
<html lang='en'>
	<head>
	<meta charset='UTF-8'>
	<title>计时器</title>
	</head>
	<body>
		<div class="time " ><span id="pastTime">00:00:00</span></div><br>
		<hr>
		<input type="button" id="logIn" value="确认" onclick="toDo()"></div>
		<script>
			var counter = 0;
			setInterval(function () {
			var worker=new Worker("javascript/myjs.js");
			worker.onmessage = function (event) {
				counter = event.data.counter;
				var m=parseInt(counter/3000);
				var s=parseInt((counter%3000)/50);
				var ms=parseInt(counter%50);
				document.getElementById("pastTime").innerHTML=toDub(m)+":"+toDub(s)+":"+toDub(ms);
			};
			//补零
			function toDub(n){
				return n<10?"0"+n:""+n;
			}
			function toDo(){
				if (confirm("继续?")){}
			}
		</script>
	</body>
</html>

 

 

 

但是,如果将这段代码交给Web Worker去运行的话,那么情况就不一样了:浏览器会在后台启动一个独立的worker线程来专门负责这段代码的运行,因此,页面在这段Javascript代码运行期间依然可以响应用户的其他操作。

<!DOCTYPE html>
<html lang='en'>
	<head>
	<meta charset='UTF-8'>
	<title>计时器</title>
	</head>
	<body>
		<div class="time " ><span id="pastTime">00:00:00</span></div><br>
		<hr>
		<input type="button" id="logIn" value="确认" onclick="toDo()"></div>
		<script>
			var counter = 0;
			var worker=new Worker("javascript/myjs.js");
			worker.onmessage = function (event) {
				counter = event.data.counter;
				var m=parseInt(counter/3000);
				var s=parseInt((counter%3000)/50);
				var ms=parseInt(counter%50);
				document.getElementById("pastTime").innerHTML=toDub(m)+":"+toDub(s)+":"+toDub(ms);
			};
			//补零
			function toDub(n){
				return n<10?"0"+n:""+n;
			}
			function toDo(){
				if (confirm("继续?")){}
			}
		</script>
	</body>
</html>

myjs.js代码:

	
var counter = 0;
setInterval(function () {counter++;	postMessage({counter});},1000/50);

改成这样就可以解决“确认”对话框导致计时器停止的问题了。

使用Web Worker,注意一下几点:

  1. 通常情况下,Worker 载入的是一个单独的 JavaScript 脚本文件,如文中的myjs.js。
  2. Worker 线程无法读取主线程所在网页的 DOM 对象。在文中,把计时器时间写到HTML对应位置只能在主线程中完成,所以在等待“确认”过程中,计时器的值也是不会变化的,但是在Worker没有暂停计时,在“确认”完成后,计时器会直接跳到正确的值显示出来。
  3. Worker 线程和主线程不能直接通信,需要通过消息完成。文中使用postMessage回传信息。

  4. Worker 线程不能执行alert()方法和confirm()方法。

  5. Worker 线程可以使用 XMLHttpRequest 对象发出 AJAX 请求。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值