JavaScript中会常常用到setTimeout来推迟一个函数的执行,如:javascript
1 setTimeout(function(){alert("Hello World");},1000)
它的意思是会在执行到这句话后延迟1秒钟(1000毫秒)来弹出alert窗口。java
那么再看这一段:
web
1 function a() { 2 setTimeout(function() {alert(1)}, 0); 3 alert(2); 4 }
注意,这段代码中的setTimeout延迟设为了0,就是延迟0毫秒,貌似是不作任何延迟马上执行。但实际的执行结果确是先弹出2再弹出1,这是为何呢?JavaScript API文档明肯定义第二个参数意义为隔多少毫秒后,回调方法就会被执行。这里设成0毫秒,理所固然就当即被执行了!?这得从Javascript调用堆栈(call stack)和setTimeout的功能提及。编程
首先,JavaScript引擎是单线程运行的,浏览器不管在何时都有且只有一个线程在运行JavaScript程序,即同一时间只执行一条代码,因此每个JavaScript代码执行块会“阻塞”其它异步事件的执行。浏览器
其次,和其余的编程语言同样,Javascript中的函数调用也是经过堆栈实现的。如上例中,在执行函数a的时候,函数a先入栈,若是不给alert(1)加setTimeout,那么alert(1)第2个入栈,最后是alert(2)。但如今给alert(1)加上setTimeout后,alert(1)就被加入到了一个新的堆栈中等待,并“尽量快”的执行。这个尽量快就是指在a的堆栈完成后就马上执行,所以实际的执行结果就是先alert(2),再alert(1)。在这里setTimeout其实是让alert(1)脱离了当前函数调用堆栈。异步
既然说JavaScript是单线程运行的,那么XMLHttpRequest在链接后是否真的异步?async
其实请求确实是异步的,不过这请求是由浏览器新开一个线程请求,当请求的状态变动时,若是先前已设置回调,这异步线程就产生状态变动事件放到 JavaScript引擎的处理队列中等待处理,当任务被处理时,JavaScript引擎始终是单线程运行回调函数,具体点即仍是单线程运行onreadystatechange所设置的函数。编程语言
1、解决双击事件触发单击事件的冲突函数
提示:默认双击会先触发单击事件,使用延迟单击事件进行处理。spa
1 function click(){ 2 isdb=false; 3 window.setTimeout(cc, 500) 4 function cc(){ 5 if(isdb!=false)return; 6 alert("单击") 7 } 8 } 9 function dblclick(){ 10 isdb=true; 11 alert("双击") 12 }
2、解决双击事件触发单击事件的冲突
AJAX请求后台,调用webservice或调用大量数据查询等状况形成前台一直处于loading加载框的状况,可使用setTimeout来解决。
部分JQ源码以下:
1 if ( s.async && s.timeout > 0 ) { 2 timeoutTimer = setTimeout(function() { 3 jqXHR.abort("timeout"); 4 }, s.timeout ); 5 }
本博文简单介绍了setTimeout和JS单线程的知识,这块水其实很深,但这边只作一个随笔。有兴趣的同窗,推荐阅读jQuery做者John的一篇文章:How JavaScript Timers Work,你会对JavaScript单线程本质和setTimeout以及setInterval有更加深入的理解。
http://ejohn.org/blog/how-javascript-timers-work/
当你理解了JS的单线程和堆栈原理,那在使用JS进行高级程序编写中,必然会驾轻就熟。
当你还在说JavaScript是一门玩具型的脚本语言时,它也在远处嘲笑你对它不够了解。