Timer
setTimeout
ist etwas, das wir häufig verwenden. Es wird verwendet, um eine Funktion aufzurufen oder einen Ausdruck nach einer bestimmten Anzahl von Millisekunden zu berechnen.
Syntax:
setTimeout(code, millisec, args);
Hinweis: Wenn der Code eine Zeichenfolge ist, entspricht dies dem Ausführen der auszuführenden Methode
eval()
der Code.
Natürlich erfahren Sie in diesem Artikel nicht nur, wie Sie
setTimeout
verwenden, sondern auch, wie es ausgeführt wird.
Sehen wir uns zunächst einen Code an:
var start = new Date(); var end = 0; setTimeout(function() { console.log(new Date() - start); }, 500); while (new Date() - start <= 1000) {}
Oben Code, definieren Ein
setTimeout
Timer wird erstellt und die Verzögerungszeit beträgt 500 Millisekunden.
Glauben Sie, dass das Druckergebnis 500 ist?
Aber Tatsache ist, dass es Ihre Erwartungen übertrifft. Das Druckergebnis ist so (vielleicht wird es anders sein, wenn Sie es ausdrucken). aber es wird definitiv größer als 1000 Millisekunden sein):
Warum ist das so? Der Grund dafür ist, dass JavaScript in einem einzelnen Thread ausgeführt wird. Mit anderen Worten: Zu jedem Zeitpunkt gibt es nur einen Thread, der das JavaScript-Programm ausführt, und es können nicht mehrere Codeteile gleichzeitig ausgeführt werden.
Werfen wir einen Blick auf JavaScript im Browser.
Der Kernel des Browsers arbeitet unter der Kontrolle des Kernels zusammen, um die Synchronisierung aufrechtzuerhalten. Ein Browser implementiert mindestens drei residente Threads: JavaScript-Engine-Thread, GUI-Rendering-Thread und Browser Ereignis auslösender Thread.
JavaScript引擎
basiert auf der ereignisgesteuerten Single-Thread-Ausführung. Die JavaScript-Engine wartet immer auf das Eintreffen von Aufgaben in der Aufgabenwarteschlange und verarbeitet diese dann nur Es kann jederzeit ein JavaScript-Thread ausgeführt werden.
GUI渲染线程
ist für das Rendern der Browseroberfläche verantwortlich (Repaint) oder ein Reflow (Reflow) wird durch einen Vorgang verursacht . Es ist jedoch zu beachten, dass sich der GUI-Rendering-Thread und die JavaScript-Engine gegenseitig ausschließen. Wenn die JavaScript-Engine ausgeführt wird, wird der GUI-Thread angehalten und GUI-Updates werden in einer Warteschlange gespeichert und sofort ausgeführt, wenn die JavaScript-Engine ausgeführt wird Motor ist im Leerlauf.
事件触发线程
: Wenn ein Ereignis ausgelöst wird, fügt der Thread das Ereignis am Ende der ausstehenden Warteschlange hinzu und wartet auf die Verarbeitung durch die JavaScript-Engine. Diese Ereignisse können aus dem Codeblock stammen, der derzeit von der JavaScript-Engine ausgeführt wird, z. B. setTimeout, oder von anderen Threads im Browserkernel, z. B. Mausklicks, asynchronen Ajax-Anforderungen usw. Dies liegt jedoch an der Single-Thread-Beziehung von JavaScript , alle diese Ereignisse müssen in die Warteschlange gestellt und auf die Verarbeitung durch die JavaScript-Engine gewartet werden (Asynchroner Code wird nur ausgeführt, wenn kein synchroner Code im Thread ausgeführt wird).
Sehen wir uns hier noch einmal das ursprüngliche Beispiel an:
var start = new Date(); var end = 0; setTimeout(function() { console.log(new Date() - start); }, 500); while (new Date() - start <= 1000) {}
Obwohl die Verzögerungszeit von
setTimeout
500 Millisekunden beträgt , aber aufgrund der Existenz der
while
-Schleife springt die while-Schleife nur dann heraus, wenn das Intervall größer als 1000 Millisekunden ist. Das heißt, vor 1000 Millisekunden belegt die while-Schleife die JavaScript-Thread. Mit anderen Worten: Erst nachdem der Thread darauf gewartet hat, aus while herauszuspringen, wird er in den Leerlauf versetzt und führt den zuvor definierten setTimeout aus.
Abschließend können wir daraus schließen, dass
setTimeout
nur garantieren kann, dass die Aufgabe (Funktion, die ausgeführt werden muss) in die Aufgabenwarteschlange eingefügt wird, um nach der angegebenen Zeit zu warten, aber Es gibt keine Garantie dafür, dass diese Aufgabe ausgeführt wird. Sobald der Thread, der das Javascript ausführt, frei ist, entfernen Sie die Aufgabe aus der Warteschlange und führen Sie sie aus.
Da der JavaScript-Thread nicht durch zeitaufwändige Vorgänge blockiert wird, kann er die Aufgaben in der Warteschlange schnell herausnehmen und ausführen. Es ist auch dieser Warteschlangenmechanismus, der für uns die Illusion einer asynchronen Ausführung erzeugt .
Vielleicht haben Sie den folgenden Code gesehen:
setTimeout(function(){ // statement}, 0);
Der obige Code bedeutet sofortige Ausführung. Die ursprüngliche Absicht besteht darin, die aufrufende Funktion sofort auszuführen, aber tatsächlich wird der obige Code nicht sofort ausgeführt. Dies liegt daran, dass setTimeout eine minimale Ausführungszeit hat. Wenn die angegebene Zeit kürzer als diese Zeit ist, verwendet der Browser die minimal zulässige Zeit time als setTimeout. Das heißt, selbst wenn wir die Verzögerungszeit von setTimeout auf 0 setzen, startet das aufgerufene Programm nicht sofort.
Die tatsächliche Situation verschiedener Browser ist unterschiedlich. Die Zeitgenauigkeit von IE8 und früheren IE beträgt 15,6 ms. Mit dem Aufkommen von HTML5 beträgt das definierte Mindestzeitintervall jedoch nicht weniger als 4 Millisekunden. Wenn es unter diesem Wert liegt, wird es automatisch erhöht, und zwar im Jahr 2010 und später konsistent in allen veröffentlichten Browsern übernommen.
Wenn wir also
setTimeout(fn,0)
schreiben, implementieren wir tatsächlich die Warteschlangensprungoperation, bei der der Browser „so schnell wie möglich“ zurückrufen muss, aber das ist tatsächlich möglich Bald kommt es auf den Browser an.
Dann
setTimeout(fn, 0)
Was nützt es? Tatsächlich liegt der Nutzen darin, dass wir die Reihenfolge der Aufgabenausführung ändern können! Weil der Browser die in der setTimeout-Warteschlange angesammelten Aufgaben ausführt, nachdem er die Aufgaben in der aktuellen Aufgabenwarteschlange abgeschlossen hat.
Indem Sie die nach der Verzögerung auszuführende Aufgabe auf 0s setzen, können Sie die Reihenfolge der Aufgabenausführung ändern, das Auftreten der Aufgabe verzögern und sie asynchron ausführen lassen.
Schauen wir uns ein beliebtes Beispiel im Internet an:
document.querySelector('#one input').onkeydown = function() { document.querySelector('#one span').innerHTML = this.value; }; document.querySelector('#second input').onkeydown = function() { setTimeout(function() { document.querySelector('#second span').innerHTML = document.querySelector('#second input').value; }, 0); };
`实例:实例
当你往两个表单输入内容时,你会发现未使用setTimeout函数的只会获取到输入前的内容,而使用setTimeout函数的则会获取到输入的内容。
这是为什么呢?
因为当按下按键的时候,JavaScript 引擎需要执行 keydown 的事件处理程序,然后更新文本框的 value 值,这两个任务也需要按顺序来,事件处理程序执行时,更新 value值(是在keypress后)的任务则进入队列等待,所以我们在 keydown 的事件处理程序里是无法得到更新后的value的,而利用 setTimeout(fn, 0),我们把取 value 的操作放入队列,放在更新 value 值以后,这样便可获取出文本框的值。
未使用setTimeout函数,执行顺序是:`onkeydown => onkeypress => onkeyup
使用setTimeout函数,执行顺序是:
onkeydown => onkeypress => function => onkeyup`
虽然我们可以使用
keyup
来替代
keydown
,不过有一些问题,那就是长按时,
keyup
并不会触发。
长按时,keydown、keypress、keyup的调用顺序:
keydown keypress keydown keypress ... keyup
也就是说keyup只会触发一次,所以你无法用keyup来实时获取值。
我们还可以用
setImmediate()
来替代
setTimeout(fn,0)
:
if (!window.setImmediate) { window.setImmediate = function(func, args){ return window.setTimeout(func, 0, args); }; window.clearImmediate = window.clearTimeout; }
setImmediate()`方法用来把一些需要长时间运行的操作放在一个回调函数里,在浏览器完成后面的其他语句后,就立刻执行这个回调函数,必选的第一个参数func,表示将要执行的回调函数,它并不需要时间参数。
注意:目前只有IE10支持此方法,当然,在Nodejs中也可以调用此方法。
3.1 setTimeout中回调函数的this
由于setTimeout() 方法是浏览器 window 对象提供的,因此第一个参数函数中的this其实是指向window对象,这跟变量的作用域有关。
看个例子:
var a = 1; var obj = { a: 2, test: function() { setTimeout(function(){ console.log(this.a); }, 0); } }; obj.test(); // 1
不过我们可以通过使用bind()方法来改变setTimeout回调函数里的this
var a = 1; var obj = { a: 2, test: function() { setTimeout(function(){ console.log(this.a); }.bind(this), 0); } }; obj.test(); // 2
3.2 setTimeout不止两个参数
我们都知道,setTimeout的第一个参数是要执行的回调函数,第二个参数是延迟时间(如果省略,会由浏览器自动设置。在IE,FireFox中,第一次配可能给个很大的数字,100ms上下,往后会缩小到最小时间间隔,Safari,chrome,opera则多为10ms上下。)
其实,setTimeout可以传入第三个参数、第四个参数….,它们表示神马呢?其实是用来表示第一个参数(回调函数)传入的参数。
setTimeout(function(a, b){ console.log(a); // 3 console.log(b); // 4},0, 3, 4);
以上就是JavaScript 开发者应该知道的 setTimeout 秘密 的内容,更多相关内容请关注PHP中文网(www.php.cn)!