Timer
setTimeout
est quelque chose que nous utilisons souvent. Il est utilisé pour appeler une fonction ou calculer une expression après un nombre spécifié de millisecondes.
Syntaxe :
setTimeout(code, millisec, args);
Remarque : Si le code est une chaîne, cela équivaut à exécuter la méthode
eval()
pour exécuter le code.
Bien sûr, cet article vous explique non seulement comment utiliser
setTimeout
, mais comprend également comment il est exécuté.
Regardons d'abord un morceau de code :
var start = new Date(); var end = 0; setTimeout(function() { console.log(new Date() - start); }, 500); while (new Date() - start <= 1000) {}
Dans ce qui précède code, définissez Une minuterie
setTimeout
est créée et le temps de retard est de 500 millisecondes.
Pensez-vous que le résultat d'impression est : 500
Mais le fait est que cela dépasse vos attentes. Le résultat d'impression est comme ceci (peut-être qu'il sera différent lorsque vous l'imprimerez, mais ce sera certainement supérieur à 1000 millisecondes) :
Pourquoi ? La raison est que JavaScript est exécuté dans un seul thread. En d’autres termes, à tout moment, il n’y a qu’un seul thread exécutant le programme JavaScript, et plusieurs morceaux de code ne peuvent pas être exécutés en même temps.
Jetons un coup d'œil à JavaScript dans le navigateur.
Le noyau du navigateur est multithread. Ils coopèrent les uns avec les autres sous le contrôle du noyau pour maintenir la synchronisation. Un navigateur implémente au moins trois threads résidents : le thread du moteur JavaScript, le thread de rendu de l'interface graphique et le navigateur. fil de déclenchement d'événement.
JavaScript引擎
est basé sur une exécution monothread événementielle. Le moteur JavaScript attend toujours l'arrivée des tâches dans la file d'attente des tâches et les traite ensuite uniquement. un fil JavaScript à tout moment.
GUI渲染线程
est responsable du rendu de l'interface du navigateur. Lorsque l'interface doit être repeinte (Repaint) ou qu'une redistribution (Reflow) est provoquée par une opération, ce fil sera exécuté. . Cependant, il convient de noter que le thread de rendu de l'interface graphique et le moteur JavaScript s'excluent mutuellement. Lorsque le moteur JavaScript est exécuté, le thread de l'interface graphique sera suspendu et les mises à jour de l'interface graphique seront enregistrées dans une file d'attente et seront exécutées immédiatement lorsque le JavaScript. le moteur est au ralenti.
事件触发线程
, lorsqu'un événement est déclenché, le fil ajoutera l'événement à la fin de la file d'attente en attente, en attente de traitement par le moteur JavaScript. Ces événements peuvent provenir du bloc de code actuellement exécuté par le moteur JavaScript tel que setTimeout, ou d'autres threads du noyau du navigateur tels que des clics de souris, des requêtes asynchrones Ajax, etc. Cependant, en raison de la relation monothread de JavaScript, tous ces événements doivent être mis en file d'attente et attendus pour être traités par le moteur JavaScript (le code asynchrone ne sera exécuté que lorsqu'aucun code synchrone n'est exécuté dans le thread).
Ici, reprenons l'exemple original :
var start = new Date(); var end = 0; setTimeout(function() { console.log(new Date() - start); }, 500); while (new Date() - start <= 1000) {}
Bien que le temps de retard de
setTimeout
soit de 500 millisecondes , mais du fait de l'existence de la boucle
while
, la boucle while ne sautera que lorsque l'intervalle est supérieur à 1000 millisecondes, c'est-à-dire qu'avant 1000 millisecondes, la boucle while occupe la boucle while. Fil JavaScript. En d'autres termes, ce n'est qu'après avoir attendu de sortir de while que le thread deviendra inactif et exécutera le setTimeout précédemment défini.
Enfin, nous pouvons conclure que
setTimeout
ne peut garantir que la tâche (fonction qui doit être exécutée) sera insérée dans la file d'attente des tâches pour attendre après le temps spécifié, mais il n'y a aucune garantie que cette tâche sera quand exécutée. Une fois le thread exécutant le javascript libre, supprimez la tâche de la file d'attente et exécutez-la.
Étant donné que le thread JavaScript n'est pas bloqué en raison d'opérations fastidieuses, il peut rapidement supprimer les tâches de la file d'attente et les exécuter. C'est également ce mécanisme de file d'attente qui crée pour nous l'illusion d'une exécution asynchrone. .
Peut-être avez-vous vu le code suivant :
setTimeout(function(){ // statement}, 0);
Le code ci-dessus signifie une exécution immédiate. L'intention initiale est d'exécuter la fonction appelante immédiatement, mais en fait, le code ci-dessus n'est pas exécuté immédiatement car setTimeout a un temps d'exécution minimum. Lorsque le temps spécifié est inférieur à ce temps, le navigateur utilisera le minimum autorisé. time comme intervalle de temps setTimeout, c'est-à-dire que même si nous fixons le temps de retard de setTimeout à 0, le programme appelé ne démarre pas immédiatement.
La situation réelle des différents navigateurs est différente. La précision temporelle d'IE8 et des versions antérieures d'IE est de 15,6 ms. Cependant, avec l'émergence du HTML5, dans les versions avancées des navigateurs (Chrome, IE9, etc.), l'intervalle de temps minimum défini n'est pas inférieur à 4 millisecondes. S'il est inférieur à cette valeur, il augmentera automatiquement, et ce en 2010. et plus tard Adopté de manière cohérente dans les navigateurs publiés.
Donc, lorsque nous écrivons
setTimeout(fn,0)
, nous implémentons en fait l'opération de saut de file d'attente, obligeant le navigateur à rappeler "le plus rapidement possible", mais en réalité cela peut être plus Bientôt, tout dépend du navigateur.
Alors
setTimeout(fn, 0)
A quoi ça sert ? En fait, l’utilité réside dans le fait que nous pouvons changer l’ordre d’exécution des tâches ! Parce que le navigateur exécutera les tâches accumulées dans la file d'attente setTimeout après avoir terminé les tâches de la file d'attente des tâches actuelle.
En définissant la tâche à exécuter après un délai sur 0 s, vous pouvez modifier l'ordre d'exécution de la tâche, retarder l'occurrence de la tâche et la faire exécuter de manière asynchrone.
Regardons un exemple populaire sur Internet :
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中文网(m.sbmmt.com)!