<!DOCTYPE html> <head><title>setTimeout</title><meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> </head> <body><script> console.log("a"); //利用setTimeout延迟执行匿名函数 setTimeout(function(){console.log("b"); },100); console.log("c");</script> </body></html>运行代码,打开chrome调试器,得如下结果
这个结果很容易理解,因为我setTimeout里的内容是在100ms后执行的嘛,当然是先输出a,再输出c,100ms后再输出setTimeout里的b嘛。
咦,那Javascript这不就不是单线程了嘛,这不就可以实现多线程了?!!
其实,不是的。setTimeout没有打破JavaScript的单线程机制,它其实还是单线程。
为什么这么说呢,那就得理解setTimeout到底是个怎么回事。
请看下面的代码,猜结果:
<!DOCTYPE html> <head><title>setTimeout</title><meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> </head> <body><script> var date = new Date(); //打印才进入时的时间 console.log("first time: " + date.getTime()); //一秒后打印setTimeout里匿名函数的时间 setTimeout(function(){var date1 = new Date();console.log("second time: " + date1.getTime() );console.log( date1.getTime() - date.getTime() ); },1000); //重复操作 for(var i=0; i < 10000 ; i++){console.log(1); }</script> </body></html>看了上面的代码,猜猜输出的结果是多少呢?1000毫秒?
纳尼,怎么不是1000毫秒呢?!!!
我们再看看下面的代码:
<!DOCTYPE html> <head><title>setTimeout</title><meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> </head> <body><script> //一秒后执行setTimeout里的匿名函数,alert下 setTimeout(function(){alert("monkey"); },1000); while(true){};</script> </body></html>运行代码后!
<!DOCTYPE html> <head><title>setTimeout</title><meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> </head> <body><script> console.log("a"); setTimeout(function(){console.log("b"); },0); console.log("c"); console.log("d");</script> </body></html>运行代码结果如下:
假设你已经知道Javascript单线程的运行原理了。那么,可能会有这样的疑问:setTimeout的时间为0,都没加到处理队列的末尾,怎么会晚执行呢?不应该立即执行吗?
我的理解是,就算setTimeout的时间为0,但是它仍然是setTimeout啊,原理是不变的。所以会将其加入到队列末尾,0秒后执行。
况且,经过查找资料发现,setTimeout有一个最小执行时间,当指定的时间小于该时间时,浏览器会用最小允许的时间作为setTimeout的时间间隔,也就是说即使我们把setTimeout的毫秒数设置为0,被调用的程序也没有马上启动。
这个最小的时间间隔是多少呢?
这和浏览器及操作系统有关。在John Resig的《Javascript忍者的秘密》一书中提到–Browsers all have a 10ms minimum delay on OSX and a(approximately) 15ms delay on Windows.(在苹果机上的最小时间间隔是10毫秒,在Windows系统上的最小时间间隔大约是15毫秒),另外,MDC中关于setTimeout的介绍中也提到,Firefox中定义的最小时间间隔(DOM_MIN_TIMEOUT_VALUE)是10毫秒,HTML5定义的最小时间间隔是4毫秒。
说了这么多,setTimeout的延迟时间为0,看来没什么意义嘛,都是放在队列后执行嘛。
非也,天生我材必有用,就看你怎么用咯。抛砖迎玉下。
1、可以用setTimeout的延迟时间为0,模拟动画效果哦。
详情请见下代码:
<!DOCTYPE html> <head><title>setTimeout</title><meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> </head> <body><div id="container" style="width:100px;height:100px;border:1px solid black;"></div><div id="btn" style="width:40px;height:40px;line-height:40px;margin-top:20px;background:pink;">click</div><script> window.onload = function(){var con = document.getElementById("container");var btn = document.getElementById("btn"); //Params: i 为起始高度,num为预期高度function render(i, num) { i++;con.style.height = i + "px"; //亮点在此 if(i < num){setTimeout(function() { render(i, num);},0); } else {con = null;btn = null; }};btn.onclick = function(){ render(100, 200);}; };</script> </body></html>由于是动画,所以想看其效果,还请各位看官运行下代码哦。
<!DOCTYPE html> <head><title>setTimeout</title><meta http-equiv="Content-Type" content="text/html; charset=utf-8"/><style>#parent {width:100px;height:100px;border:1px solid black; }#child {width:50px;height:50px;background:pink; }</style> </head> <body><div id="parent"> <div id="child"></div></div><script> //点击子元素,实现子元素的事件在父元素触发后触发 window.onload = function(){var parent = document.getElementById("parent"); var child = document.getElementById("child");parent.onclick = function(){ console.log("parent");}child.onclick = function(){ //利用setTimeout,冒泡结束后,最后输出child setTimeout(function(){console.log("child");},0);}parent = null;child = null;}</script> </body></html>执行代码,点击粉红色方块,输出结果:
三、setTimeout那些事儿之this
说到this,对于它的理解就是:this是指向函数执行时的当前对象,倘若没有明确的当前对象,它就是指向window的。
好了,那么我们来看看下面这段代码:
<!DOCTYPE html> <head><title>setTimeout</title><meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> </head> <body><script> var name = "!!"; var obj = {name:"monkey",print:function(){ console.log(this.name);},test:function(){ //this.print setTimeout(this.print,1000);} } obj.test();</script> </body></html>通过chrome调试器,查看输出结果:
咦,它怎么输出的是”!!”呢?不应该是obj里的”monkey”吗?!!
这是因为setTimeout中所执行函数中的this,永远指向window。
不对吧,那上面代码中的setTimeout(this.print,1000)里的this.print怎么指向的是obj呢?!!
注意哦,我这里说的是“延迟执行函数中的this”,而不是setTimeout调用环境下的this。
什么意思?
setTimeout(this.print,1000),这里的this.print中的this就是调用环境下的;
而this.print=function(){console.log(this.name);},这个匿名函数就是setTimeout延迟执行函数,其中的this.name也就是延迟执行函数中的this啦。
嘿嘿,这下明白了吧。
var age = 24;function Fn(){ this.age = 18; setTimeout(function(){//this代表windowconsole.log(this);//输出24,而不是Fn的18console.log(this.age); },1000);}new Fn();咦,那有个疑问,比如我想在setTimeout延迟执行函数中的this指向调用的函数呢,而不是window?!!我们该怎么办呢。
var age = 24;function Fn(){ //that在此 var that = this; this.age = 18; setTimeout(function(){console.log(that);console.log(that.age); },1000);}new Fn();还有一种方法就是,利用bind。
var age = 24;function Fn(){ this.age = 18; //bind传入this setTimeout(function(){console.log(this);console.log(this.age); }.bind(this),1000);}new Fn();以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。