j'étais dans une situation délicate,
Je travaille avec du JavaScript pur depuis près de 3 ans et je sais que JavaScript est un langage monothread , et que vous pouvez simuler une exécution asynchrone en utilisant setInterval
et setTimeout
,
mais quand j'ai pensé à comment ils pouvaient fonctionner, je ne pouvais pas le comprendre clairement. Alors, comment ces fonctions affectent le contexte d'exécution?
Je suppose que dans un temps spécifique ne s'exécute qu'une partie du code et après qu'il passe à une autre partie. Si tel est le cas, un grand nombre d'appels setInterval
ou setTimeout
affecteront-ils les performances?
Javascript est un thread unique, mais pas le navigateur. Le navigateur a au moins trois threads: thread de moteur Javascript, thread d'interface utilisateur et thread de synchronisation, où la synchronisation de setTimeout
et setInterval
est effectuée par le thread de synchronisation.
Lors de l'appel de setTimeout
ou setInterval
, un thread de minuterie dans le navigateur commence le compte à rebours et lorsque le temps passe place la fonction de rappel dans la pile d'exécution du thread javascript. La fonction de rappel n'est pas exécutée avant la fin des autres fonctions au-dessus dans la pile. Par conséquent, s'il existe d'autres fonctions chronophages en cours d'exécution lorsque le temps est écoulé, le rappel de setTimeout
ne se terminera pas à temps.
Le navigateur possède une API pour la fonction Timer, tout comme l'API pour l'événement ex.
'Cliquez sur'
'faire défiler'
Supposons que vous ayez le code suivant dans votre application
function listener(){
...
}
setTimeout(listener, 300)
function foo(){
for(var i = 0; i < 10000; i++){
console.log(i)
}
}
foo()
À ce stade, selon notre code, nous avons écrit au-dessus de notre pile d'appels ressemblera
Pile d'appels -> foo
Et supposons que foo prendra 1s pour terminer son exécution, comme nous avons déjà défini 1 timeout dans notre code et nous l'exécutons avant que "foo" ne termine son exécution, c'est-à-dire à 300 ms
Que se passera-t-il alors?
Javascript arrête-t-il d'exécuter foo et commence-t-il à exécuter setTimeout?
Non
Comme nous savons déjà que javascript est un thread unique, il doit donc terminer l'exécution de foo avant d'aller de l'avant, mais comment le navigateur s'assure-t-il qu'après l'exécution de foo le "setTimeout" s'exécutera?
Ici, la magie javascript entre en scène
Lorsque 300 ms est expiré, le "Timer API" du navigateur entre en action et place le gestionnaire de délai d'attente dans "Message Queue"
À ce stade, "Message Queue" dans l'image ci-dessus ressemblera
Message Queue -> setTimout: listner
Et
Pile d'appels -> foo
Et lorsque "Call Stack" devient vide, c'est-à-dire que foo termine son exécution, la "Event Loop" comme indiqué dans l'image prendra le message de la file d'attente de messages et le poussera dans la pile
Le seul travail de "Boucle d'événement" est lorsque "Pile d'appels" devient vide et que "File d'attente de messages" y est entré, puis retirez le formulaire de message "File d'attente de messages" et poussez-le dans "Pile d'appels"
À ce stade, la file d'attente de messages dans l'image ci-dessus ressemblera
File d'attente des messages ->
Et
Pile d'appels -> auditeur
Et c'est ainsi que setTimeout et setInterval fonctionnent, même si nous spécifions 300 ms dans setTimeout, il s'exécutera une fois que "foo" aura terminé son exécution dans ce cas, c'est-à-dire après 1s. Et c'est pourquoi la minuterie spécifiée dans setTimeout/setInterval indique "Minimum Time" délai pour l'exécution de la fonction.
Javascript est un thread unique, mais pas le navigateur.
Il y a 1 pile où la fonction et les instructions sont exécutées. il y a 1 file d'attente où la fonction est mise en file d'attente pour être exécutée. il existe des API Web qui peuvent contenir la fonction pendant un temps particulier, définies dans setTimeout et setInterval dans la table des événements.
lorsque le moteur javascript exécute le fichier js ligne par ligne, s'il trouve une ligne comme instruction ou fonction, il la charge sur la pile et s'exécute mais s'il s'agit d'un appel setTimeout ou setInterval, le gestionnaire de fonctions associé à setTimeout ou setInterval est retiré par l'API TIME (une des API Web du navigateur) et maintenez-la pendant ce temps.
Une fois ce temps écoulé, Time Api met cette fonction en fin de file d'attente d'exécution.
Maintenant, l'exécution de cette fonction dépend d'autres appels de fonctions qui sont en avance dans la file d'attente.
Remarque: cet appel de fonction est appelé sur un objet window.
setTimeout(function () {console.log(this)}, 300)
Fenêtre {postMessage: ƒ, flou: ƒ, focus: ƒ, fermeture: ƒ, cadres: fenêtre,…}
JavaScript est un langage de script à thread unique, il peut donc exécuter un morceau de code à la fois (en raison de sa nature à thread unique), chacun de ces blocs de code "bloque" la progression d'autres événements asynchrones. Cela signifie que lorsqu'un événement asynchrone se produit (comme un clic de souris, un déclenchement de minuterie ou une fin de XMLHttpRequest), il est mis en file d'attente pour être exécuté plus tard.
setTimeout () lorsque vous utilisez setTimeout (), il ne s'exécutera que lorsque son tour arrivera dans une file d'attente, si un événement antérieur (de setTimeout) se bloque pour une raison quelconque setTimeout peut être retardé par rapport au temps spécifié dans Fonction setTimeout (). lors de l'exécution de la fonction de rappel setTimeout, si un événement se produit (par exemple, un événement de clic), il est mis en file d'attente pour être exécuté plus tard.
setTimeout(function(){
/* Some long block of code... */
setTimeout(arguments.callee, 10);
}, 10);
setInterval(function(){
/* Some long block of code... */
}, 10);
setInterval ()
Similaire à setTimeout mais appelle continuellement la fonction (avec un retard à chaque fois) jusqu'à ce qu'elle soit annulée.
le code setTimeout aura toujours un délai d'au moins 10 ms après la
exécution de rappel précédente (cela peut finir par être plus, mais jamais moins) alors que setInterval tentera d'exécuter un rappel toutes les 10 ms, indépendamment du moment où le dernier rappel a été exécuté.
Si une minuterie est bloquée pour s'exécuter immédiatement, elle sera retardée
jusqu'au prochain point d'exécution possible (qui sera plus long que le délai souhaité). Les intervalles peuvent s'exécuter consécutivement sans délai s'ils prennent suffisamment de temps pour s'exécuter (plus long que le délai spécifié).
retard).
Juste une note en ce qui concerne mon expérience, si vous allez utiliser setTimeout (), la fonction sera toujours retardée (et je veux dire exécutée plus tard) ou exécutée après un code supplémentaire qui n'est pas 'expiré'. Cela peut se produire même avec des fonctions qui ont delay = 0 et qui sont provoquées par la boucle d'événement.
Voir l'exemple ci-dessous:
setTimeout(function() {
console.log('Second');
}, 0)
console.log('First');