大多数程序员都被setInterval坑过吧,如果不是高并发,程序执行快,可能还不知道怎么回事。
模拟一个场景, 假如我们需要一个client.html ,每隔一秒,返回服务器sleep.php处理后的时间。
这个需求很简单,直接上代码吧。 client.html代码如下
<html>
<head>
<meta charset="utf-8">
</head>
<script src="//libs.baidu.com/jquery/1.8.3/jquery.min.js"></script>
<body>
<script type="text/javascript">
function test(){
$.get('sleep.php',function(data){console.log(data);});
}
setInterval(test,1000);
</script>
</body>
</html>
服务端程序sleep.php如下
<?php
echo date('H:i:s');
?>
用浏览器打开 htpt://localhost/client.html ,并打开控制台,程序工作的很好,非常完美。
有一天程序特别受欢迎, 用户暴涨并发到了几百上千, sleep的程序也变得更复杂了,加入了一个复杂的业务比如计费系统,导致sleep.php 执行的时间非常长,模拟一下sleep.php 需要3秒。为了sleep.php 好看,老朱代码改成了下面的样子。
<?php
while(true){
if(time()%3==0){
echo date('H:i:s');
exit;
}
sleep(1);
}
?>
这时候刷新http://localhost/client.html ,看控制台,神奇的事情发生了。间隔三秒输出,但是输出的时间变成了3个,看红色标注的部分。也就是客户端对服务器发起了3个并发连接,现实是sleep.php 执行的时间越长,client.html 间隔请求的时间越短,导致的并发越多(除非受限浏览器连接数) 。对于高并发,很可能就雪崩了。
那如何避免这种情况出现呢?怎么真正的实现每间隔一秒去服务器获取一次数据呢? 先看看interval和setTimeout的区别吧。
setInterval
setInterval()方法可按照指定的周期来调用函数或者计算表达式(以毫秒为单位)
语法:
setInterval(函数表达式,毫秒数);
setInterval()会不停的调用函数,直到clearInterval()被调用或者窗口被关闭,由 setInterval()返回的ID值可用作clearInterval()方法的参数。
setTimeout
setTimeout()方法用于在指定毫秒数后再调用函数或者计算表达式(以毫秒为单位)
语法:
setTimeout(函数表达式,毫秒数);
setTimeout()只执行函数一次,如果需要多次调用可以使用setInterval(),或者在函数体内再次调用setTimeout()
区别
通过以上分析可以看出,setTimeout与setInterval的主要区别是:
setTimeout()方法只运行一次,也就是说当达到设定的时间后就出发运行指定的代码,运行完后就结束了,如果还想再次执行同样的函数,可以在函数体内再次调用setTimeout(),可以达到循环调用的效果。
setInterval()是循环执行的,即每达到指定的时间间隔就执行相应的函数或者表达式,是真正的定时器。
明白两个函数的区别,client.html这个程序稍微做一下改动就可以了。
<html>
<head>
<meta charset="utf-8">
</head>
<script src="//libs.baidu.com/jquery/1.8.3/jquery.min.js"></script>
<body>
<script type="text/javascript">
setTimeout(test,1000);
function test(){
$.get('sleep.php',function(data){
console.log(data);
setTimeout(test,1000);
});
}
</script>
</body>
</html>
再次刷新页面,并发消失,并且在服务器sleep.php执行完成后,再请求服务器的内容。