長い間、ブラウザーで JavaScript プログラムを実行するスレッドが 1 つだけであっても、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 後はもちろん、100ms 後の setTimeout で最初に a を出力し、次に c を出力し、次に 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ミリ秒?
Chrome デバッガーを開きます。下の図を参照してください
ナニ、なぜ 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>
コードを実行した後!
なんてことだ、なぜ私は更新し続けるのですか、ブラウザはスタックしており、警告もありません。 !
論理的には、無限ループしたとしても、1 秒後にはアラートを発する必要があります。
あらゆる種類の問題には同じ理由があります。JavaScript はシングルスレッドです。
JavaScript はシングルスレッドであり、setTimeout はマルチスレッドを実装していないことに注意してください。その背後にある真実は次のとおりです:
JavaScript エンジンは単一スレッドで実行され、ブラウザーのみが 1 つのスレッドで JavaScript を実行します。いつでもプログラム。
ブラウザのカーネルは、カーネルの制御下で相互に連携して、JavaScript エンジン スレッド、GUI レンダリング スレッド、ブラウザ イベント トリガーの 3 つの常駐スレッドを実装します。スレッド 。
*JavaScript エンジン は、イベント駆動型のシングルスレッド実行に基づいており、JavaScript エンジンはタスク キュー内のタスクの到着を常に待機し、それを実行する JavaScript スレッドが 1 つだけあります。いつでもJavaScriptプログラム。
*GUIレンダリングスレッドは、ブラウザインターフェースのレンダリングを担当します。このスレッドは、インターフェースの再描画(Repaint)が必要な場合、または何らかの操作によってリフロー(Reflow)が発生した場合に実行されます。ただし、GUI レンダリング スレッドと JavaScript エンジンは相互に排他的であることに注意してください。JavaScript エンジンが実行されると、GUI スレッドは一時停止され、GUI の更新はキューに保存され、JavaScript が実行されるとすぐに実行されます。エンジンはアイドル状態です。
*イベントトリガースレッド。イベントがトリガーされると、スレッドは保留中のキューの最後にイベントを追加し、JavaScript エンジンによる処理を待ちます。これらのイベントは、setTimeout などの JavaScript エンジンによって現在実行されているコード ブロックから、またはマウス クリックや Ajax 非同期リクエストなどのブラウザ カーネル内の他のスレッドから発生する可能性があります。ただし、JavaScript のシングルスレッド関係により、すべてのイベントが発生します。これらのイベントは、JavaScript エンジンによる処理のためにキューに入れられる必要があります (スレッド内で同期コードが実行されていない場合にのみ、非同期コードが実行されます)。
したがって、上記の説明を通じて、上記の問題はすべて簡単に解決できます。
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 に設定され、呼び出されたプログラムはすぐには開始されません。
最小時間間隔はどれくらいですか?
这和浏览器及操作系统有关。在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> <p id="container" style="width:100px;height:100px;border:1px solid black;"></p> <p id="btn" style="width:40px;height:40px;line-height:40px;margin-top:20px;background:pink;">click</p> <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>
由于是动画,所以想看其效果,还请各位看官运行下代码哦。
代码第19行中,利用setTimeout,在每一次render执行完成(给高度递增1)后,由于Javascript是单线程,且setTimeout里的匿名函数会在render执行完成后,再执行render。所以可以实现动画效果。
2、可以用setTimeout的延迟时间为0,实现捕获事件哦。
当我们点击子元素时,我们可以利用setTimeout的特性,来模拟捕获事件。
请见如下代码:
<!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> <p id="parent"> <p id="child"></p> </p> <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>
执行代码,点击粉红色方块,输出结果:
说到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代表window console.log(this); //输出24,而不是Fn的18 console.log(this.age); },1000); } new Fn();
咦,那有个疑问,比如我想在setTimeout延迟执行函数中的this指向调用的函数呢,而不是window?!!我们该怎么办呢。
常用的方法就是利用that。
that?
对,that。利用闭包的知识,让that保证你传进去的this,是你想要的。
详情见下:
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();
以上就是JavaScript 中 setTimeout的代码详情介绍的内容,更多相关内容请关注PHP中文网(www.php.cn)!