Maison >interface Web >js tutoriel >Introduction au mécanisme JavaScript monothread et au principe d'exécution setTimeout (avec code)
Le contenu de cet article est une introduction au mécanisme JavaScript monothread et au principe d'exécution setTimeout (avec code). Il a une certaine valeur de référence. Les amis dans le besoin peuvent s'y référer.
Mécanisme monothread du moteur Javascript
Tout d'abord, il est clair que le moteur JavaScript est un mécanisme monothread.
JavaScript est exécuté dans un seul thread et ne peut pas exécuter plusieurs morceaux de code en même temps. Lorsqu'un certain morceau de code est en cours d'exécution, toutes les tâches suivantes doivent attendre, formant une file d'attente de tâches. Une fois la tâche en cours exécutée, la tâche suivante est retirée de la file d'attente, ce qui est souvent appelé « exécution bloquante ».
peut être compris comme : le code asynchrone ne sera exécuté que s'il n'y a pas de code synchrone à exécuter dans le thread JS
Donc un clic de souris, ou le timer atteint le point temporel, ou la requête Ajax est terminé Lorsqu'une fonction de rappel est déclenchée, ces gestionnaires d'événements ou fonctions de rappel ne s'exécuteront pas immédiatement, mais seront immédiatement mis en file d'attente et exécutés une fois le thread libre. Si le thread JavaScript actuel exécute un code fastidieux et qu'un clic de souris se produit, le gestionnaire d'événements sera bloqué et l'utilisateur ne pourra pas voir les commentaires immédiatement. Le gestionnaire d'événements sera placé dans la file d'attente des tâches jusqu'au précédent. L'exécution ne commencera qu'à la fin du code. Si un setTimeout est défini dans le code, le navigateur insérera le code dans la file d'attente des tâches au moment approprié. Si ce temps est défini sur 0, cela signifie qu'il sera immédiatement inséré dans la file d'attente, mais il ne sera pas exécuté. immédiatement. Il faudra encore attendre que le code précédent soit exécuté. Par conséquent, setTimeout ne garantit pas le temps d'exécution. Le fait qu'il soit exécuté à temps dépend du fait que le thread JavaScript soit encombré ou inactif.Le mécanisme multi-thread du navigateur et la boucle d'événements
Tout d'abord, il est clair que le noyau du navigateur est multi-thread. Ils coopèrent les uns avec les autres sous le contrôle du noyau pour maintenir la synchronisation. navigateur au moins Implémentez trois threads résidents :
thread du moteur javascript
thread de rendu GUI
thread de déclenchement d'événement du navigateur
Le moteur JavaScript est unique. threaded En cours d'exécution, le navigateur n'a qu'un et un seul thread exécutant le programme JavaScript à tout moment
Le moteur JavaScript est basé sur une exécution monothread basée sur les événements. Le moteur JS attend l'arrivée des tâches. dans la file d'attente des tâches, puis ajoute Processing, le navigateur n'a qu'un seul thread JS exécutant le programme JS à tout moment.
Le thread de rendu 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 thread sera exécuté. Cependant, il convient de noter que le thread de rendu GUI et le moteur JS s'excluent mutuellement lorsque le moteur JS est exécuté, le thread GUI sera suspendu et les mises à jour de l'interface graphique seront enregistrées dans une file d'attente et exécutées immédiatement lorsque le moteur JS sera exécuté. inactif.
Fil de déclenchement d'événement. Lorsqu'un événement est déclenché, le fil ajoute l'événement à la fin de la file d'attente en attente et attend son traitement par le moteur JS. 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 JS, tous ces événements doivent être mis en file d'attente pour être traités par le moteur JS. (Le code asynchrone sera exécuté lorsqu'aucun code synchrone n'est exécuté dans le thread)
Event loop (event loop) : sert à gérer notre code asynchrone, il les mettra dans un pool de threads Parmi eux
Tout d'abord, il est clair que la fonction setTimeout est un code asynchrone, mais en fait setTimeout n'est pas une véritable opération asynchrone
En raison de le mécanisme de fonctionnement des threads JS : le code asynchrone ne sera exécuté que lorsqu'aucun code synchrone n'est exécuté dans le thread. setTimeout est un code asynchrone, donc setTimeout ne peut être exécuté que lorsque js est inactif
Comme mentionné précédemment, si. a est défini dans le code setTimeout, alors le navigateur insérera le code dans la file d'attente des tâches au moment approprié. Si cette heure est définie sur 0, cela signifie qu'il sera immédiatement inséré dans la file d'attente, mais il ne sera pas exécuté. immédiatement. Il faudra encore attendre que le code précédent soit exécuté. Par conséquent, setTimeout ne garantit pas le temps d'exécution. Le fait qu'il soit exécuté à temps dépend du fait que le thread JavaScript soit encombré ou inactif.
C'est-à-dire que setTimeout peut uniquement garantir que la tâche (fonction qui doit être exécutée) sera insérée dans la file d'attente pour attendre après le temps spécifié. Il ne garantit pas quand la tâche sera exécutée. Le thread exécutant JavaScript retirera la tâche de la file d'attente et l'exécutera lorsqu'il sera inactif. JavaScript utilise ce mécanisme de file d'attente pour nous donner l'illusion d'une exécution asynchrone.
Parfois, le code dans setTimeout sera exécuté rapidement, et nous aurons l'impression que ce code est exécuté de manière asynchrone. En effet, le thread JavaScript n'est pas bloqué en raison d'opérations fastidieuses, il peut donc être rapidement supprimé. de la file d’attente. La tâche dans la file d’attente est ensuite exécutée.
Exemple d'analyse
Après avoir la base théorique ci-dessus, nous analysons les exemples suivants :
======= ==== ================================
var t = true; window.setTimeout(function (){ t = false; },1000); while (t){} alert('end');
Résultat d'exécution : le programme est bloqué dans un boucle infinie, t = false
ne peut pas être exécuté, donc alert('end')
ne sera pas exécuté.
Analyse :
JS是单线程的,所以会先执行 while(t){} 再 alert,但这个循环体是死循环,所以永远不会执行alert。
为什么不执行 setTimeout?是因为JS的工作机制是:当线程中没有执行任何同步代码的前提下才会执行异步代码,setTimeout是异步代码,所以 setTimeout 只能等JS空闲才会执行,但死循环是永远不会空闲的,所以 setTimeout 也永远得不到执行。
===========================================
var start = new Date(); setTimeout(function(){ var end = new Date(); console.log("Time elapsed: ", end - start, "ms"); }, 500); while (new Date - start <= 1000){}
运行结果:"Time elapsed: 1035 ms" (这里的1035不准确 但是一定是大于1000的)
解析:
JS是单线程 setTimeout 异步代码 其回调函数执行必须需等待主线程运行完毕
当while循环因为时间差超过 1000ms 跳出循环后,setTimeout 函数中的回调才得以执行
===========================================
for(var i=0;i<10;i++){ setTimeout(function() { console.log(i); }, 0); }
运行结果:输出10个10
解析:JS单线程 setTimeout 异步代码 任务队列
问:如何修改可以使上述代码输出 0123456789
自执行函数 或 使用ES6中的let关键字
// 自执行函数 形成闭包 记忆其被创建时的环境 for(var i=0;i<10;i++){ setTimeout((function() { console.log(i); })(), 0); }
现在我们了解了setTimeout函数执行的原理,那么它有什么作用呢?
setTimeout函数增加了Javascript函数调用的灵活性,为函数执行顺序的调度提供极大便利。
简言之,改变顺序,这正是setTimeout(0)的作用。
使用场景示例:
<input type="text" onkeydown="show(this.value)"> <p></p> <script type="text/javascript"> function show(val) { document.getElementsByTagName('p')[0].innerHTML = val; } </script>
这里绑定了 keydown 事件,意图是当用户在文本框里输入字符时,将输入的内容实时地在
中显示出来。但是实际效果并非如此,可以发现,每按下一个字符时,
中只能显示出之前的内容,无法得到当前的字符。
修改代码:
<input type="text" onkeydown="var self=this; setTimeout(function(){show(self.value)}, 0)"> <p></p> <script type="text/javascript"> function show(val) { document.getElementsByTagName('p')[0].innerHTML = val; } </script>
这段代码使用setTimeout(0)就可以实现需要的效果了。
这里其实涉及2个任务,1个是将键盘输入的字符回写到输入框中,一个是获取文本框的值将其写入p中。第一个是浏览器自身的默认行为,一个是我们自己编写的代码。很显然,必须要先让浏览器将字符回写到文本框,然后我们才能获取其内容写到p中。改变顺序,这正是setTimeout(0)的作用。
其他应用场景:有时候,加载一些广告的时候,我们用setTimeout实现异步,好让广告不会阻塞我们页面的渲染。
如果一个计时器被阻塞而不能立即执行,它将延迟执行直到下一次可能执行的时间点才被执行(比期望的时间间隔要长些)
如果setInterval回调函数的执行时间将足够长(比指定的时间间隔长),它们将连续执行并且彼此之间没有时间间隔。
本篇文章到这里就已经全部结束了,更多其他精彩内容可以关注PHP中文网的JavaScript视频教程栏目!
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!