JavaScript中setTimeout的那些东西
首先,setTimeout是其中的一个线程
一直以来,大家都说Javascript是单线程,无论浏览器什么时候运行JavaScript程序,都只有一个线程在运行。
不过,不知道大家有没有问题。——是我们在编程过程中的setTimeout(类似于setInterval和Ajax),不是异步执行的吗?
例如:
!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脚本var Date=new Date();//打印time console . log(' first time : ' date . gettime());//一秒后打印setTimeout中匿名函数的时间(函数(){ vardate 1=new date();console . log(' second time : ' date 1 . GetTime());console . log(date 1 . gettime()-date . gettime());},1000);//对(var i=0)重复操作;我10000;I){ console . log(1);} /script /body/html看完上面的代码,猜猜输出是什么?1000毫秒?
让我们打开chrome调试器,如下所示
纳尼,为什么不是1000毫秒?
让我们看看下面的代码:
!DOCTYPE html head title settimeout/title meta http-equiv=' Content-Type ' Content=' text/html;charset=utf-8 '//header dyscript//一秒后执行setTimeout中的匿名函数,并在alert下执行setTimeout(function(){ alert(' monkey ');},1000);while(true){ };/script/body/html运行代码后!
为什么一直清爽?浏览器卡住了,没有警报!
事实上,即使我无限循环,1秒钟后我也必须保持警惕。
各种问题都是一个原因。JavaScript是单线程的。
请记住,JavaScript是单线程的,setTimeout不实现多线程。背后的真相是这样的:
JavaScript引擎在单个线程上运行,浏览器在任何时候都只在一个线程上运行JavaScript程序。
浏览器内核是多线程的,它们相互协作,在内核的控制下保持同步。一个浏览器至少实现三个常驻线程:JavaScript引擎线程、GUI渲染线程和浏览器事件触发线程。
*JavaScript引擎基于事件驱动的单线程执行。JavaScript引擎一直在等待任务队列中任务的到来,然后处理它们。浏览器中任何时候都只有一个JavaScript线程在运行JavaScript程序。
*GUI渲染线程负责渲染浏览器界面,当界面因某种操作需要重绘或回流时会执行。然而,应该注意的是,图形用户界面渲染线程与JavaScript引擎是互斥的。当JavaScript引擎执行时,GUI线程将被挂起,GUI更新将被保存在队列中,并在JavaScript引擎空闲时立即执行。
* event触发一个线程,当一个事件被触发时,线程会将一个事件添加到待处理队列的末尾,等待JavaScript引擎处理。这些事件可以来自JavaScript引擎当前执行的代码块,如setTimeout,也可以来自浏览器内核的其他线程,如鼠标点击、Ajax异步请求等。但是由于JavaScript的单线程关系,所有这些事件都要排队等待JavaScript引擎处理(只有线程中没有执行同步代码时才会执行异步代码)。
所以,通过上面的解释,上面的问题就很容易解决了。
第二,setTimeout那些东西的延迟时间是0
当setTimeout的延迟时间为0时,你认为会如何执行?
例如,以下代码:
!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,被调用的程序也不会立即启动。
最短时间间隔是多少?
这与浏览器和操作系统有关。在约翰瑞西的书《Javascript忍者的秘密》中,提到了——浏览器在OS X的最小延迟都是10毫秒,在Windows上的延迟(大约)是15毫秒。(Mac上的最小时间间隔为10ms。Windows系统上的最小时间间隔约为15毫秒。此外,MDC中setTimeout的介绍也提到,Firefox中定义的最小时间间隔(DOM_MIN_TIMEOUT_VALUE)为10ms,HTML5中定义的最小时间间隔为4ms。
话虽如此,setTimeout的延迟时间是0,这似乎没有太大意义。它们都是在队列之后执行的。
不,既然上天给了人才,那就让它就业吧!这取决于你如何使用它。抛砖引玉。
1.可以使用延迟时间为0的setTimeout来模拟动画效果。
详情请参考以下代码:
!DOCTYPE html head title settimeout/title meta http-equiv=' Content-Type ' Content=' text/html;charset=utf-8 '/head body div id=' container ' style=' width :100 px;高度:100 px;' border:1px纯黑;'/div div id=' BTN ' style=' width :40 px;高度:40 px;线高:40 px;margin-top :20 px;background:pink'click/div script window . onload=function(){ var con=document . getelementbyid(' container ');var BTN=document . getelementbyid(' BTN ');//params 3360 I为起始高度,num为期望高度函数render(i,num){ I;con . style . height=I ' px ';//这里的亮点是if(I num){ settimeout(function(){ render(I,num);},0);} else { con=nullbtn=null} };BTN . onclick=function(){ render(100,200);};};/script /body/html因为是动画,我想看看它的效果。请阅读代码并运行它。
在代码的第19行,使用setTimeout,在每次渲染执行完成后(高度增加1),因为Javascript是单线程的,setTimeout中的匿名函数将在渲染执行完成后执行渲染。可以实现动画效果。
2.您可以通过将setTimeout的延迟时间设置为0来捕获事件。
当我们点击子元素时,我们可以使用setTimeout的特性来模拟捕获事件。
请参见以下代码:
!DOCTYPE html标题title settimeout/title meta http-equiv=' Content-Type ' Content=' text/html;charset=utf-8 '/style # parent { width :100 px;高度:100 pxborder:1px纯黑;} # child { width:50px高度:50 px背景:粉红色;}/style/head body div id=' parent ' div id=' child '/div/div脚本/点击子元素,实现子元素的事件在父元素触发后触发窗户。onload=function(){ var parent=document。getelementbyid(' parent ');var child=文档。getelementbyid(' child ');父母。onclick=function(){ console。日志('父');} child.onclick=function(){ //利用setTimeout,冒泡结束后,最后输出child setTimeout(函数(){ console。日志('子');},0);} parent=nullchild=null}/脚本/正文/html执行代码,点击粉红色方块,输出结果:
三、设置超时那些事儿之这
说到这个,对于它的理解就是:这个是指向函数执行时的当前对象,倘若没有明确的当前对象,它就是指向窗户的。
好了,那么我们来看看下面这段代码:
!DOCTYPE html标题title settimeout/title meta http-equiv=' Content-Type ' Content=' text/html;charset=utf-8 '/头体脚本var name='!';var obj={ name:'monkey ',print : function(){ console。日志(这个。姓名);},测试:函数(){//this。打印setTimeout(这个。打印,1000张);} } obj。test();/脚本/正文/html通过铬调试器,查看输出结果:
咦,它怎么输出的是"!"呢?不应该是目标文件里的"猴子"吗?
这是因为setTimeout中所执行函数中的这个,永远指向窗户。
不对吧,那上面代码中的setTimeout(this.print,1000)里的这个。打印怎么指向的是目标文件呢?
注意哦,我这里说的是"延迟执行函数中的这个",而不是setTimeout调用环境下的这个。
什么意思?
setTimeout(this.print,1000),这里的这个。打印中的这就是调用环境下的;
而这个。print=function(){ console。日志(这个。姓名);},这个匿名函数就是setTimeout延迟执行函数,其中的这个名字也就是延迟执行函数中的这啦。
嘿嘿,这下明白了吧。
定义变量年龄=24岁;函数Fn(){这个。年龄=18岁;setTimeout(函数(){//这个代表window console.log(此);//输出24,而不是【数学】函数的18控制台。日志(这个。年龄);},1000);} new Fn();咦,那有个疑问,比如我想在setTimeout延迟执行函数中的这指向调用的函数呢,而不是窗户?我们该怎么办呢。
常用的方法就是利用那个。
那个吗?
对,那个。利用闭包的知识,让那保证你传进去的这个,是你想要的。
详情见下:
定义变量年龄=24岁;函数Fn(){//即在此变量=这个;this . age=18 settimeout(function(){ console。日志(即);控制台日志;},1000);} new Fn();还有一种方法就是,利用装订。
如下:
定义变量年龄=24岁;函数Fn(){这个。年龄=18岁;//绑定传入此setTimeout(函数(){控制台。日志(这个);控制台。日志(这个。年龄);}.绑定(本),1000);} new Fn();以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。
版权声明:JavaScript中setTimeout的那些东西是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。