JavaScript如何实现sleep?
一般的,sleep
是将当前上下文所在的线程从执行状态转化为挂起状态,直到指定的一段实时时间过去后,再从挂起状态转化为执行状态,在sleep执行结束前,线程不会执行其他任务。
该函数使当前进程从执行状态转化为挂起状态,直到参数seconds所指定的一段实时时间过去后,或者是一个唤醒信号跟踪功能或终止进程功能的信号到来。该挂起时间由于系统的其他调度活动可能会比要求的时间长。
在ES标准中,JavaScript代码的执行环境是一个单线程环境,所以JavaScript如何实现sleep
的本质是如何将一个线程阻塞一段时间然后继续工作。
这里的重点是阻塞
。所以,使用promise
、generator
之类的实现是不满足这个需求的,任务调度机制本质不同,因为promise
、generator
的本质是延迟,而不是阻塞。
在不扩展JavaScript语言底层能力的情况下,实现阻塞方式:
- 计算阻塞
- IO阻塞
计算阻塞
也就是消耗CPU资源进行阻塞,通常是一段循环计算,在循环期间,JavaScript代码执行线程不会执行其他任务,从而达到模拟sleep
的效果
<script type="text/javascript">
// bad implementation
function sleep(milliSeconds){
var startTime = new Date().getTime(); // get the current time
while (new Date().getTime() < startTime + milliSeconds); // hog cpu
}
}
</script>
这种方式在任何标准的ES环境中都可以实现,阻塞和计时在同一个线程中完成。
IO阻塞
也就是消耗IO资源进行阻塞,通常是消耗网络IO,如XMLHttpRequest
的同步通信。
<script type="text/javascript">
function sleep(milliSeconds)
{
var resource;
var response;
if(typeof ActiveXObject == 'undefined'){
resource = new XMLHttpRequest();
}
else{
resource = new ActiveXObject("Microsoft.XMLHTTP");
}
try{
resource.open('GET', 'sleep?milliSeconds=' + milliSeconds, false);
resource.send(null);
response = resource.responseText; // JavaScript waits for response
}
catch(e){
alert(e);
}
}
</script>
这种方式是基于BS模型,Server负责计时,在指定的时间后返回响应,Browser负责阻塞。
引入扩展阻塞
参考 http://devcheater.com/,还可以引入其他语言能力实现sleep
,如Java Applet
、Flash的sleep