Fil unique JavaScript
Le threading unique de JavaScript est lié à son objectif. En tant que langage de script de navigateur, le but principal de JavaScript est d'interagir avec les utilisateurs et d'exploiter DOM. Cela détermine qu'il ne peut être qu'un seul thread, sinon il entraînera des problèmes de synchronisation très complexes. Par exemple, Supposons que JavaScript ait deux threads en même temps, un thread ajoute du contenu sur un certain nœud DOM, et l'autre thread supprime ce nœud, quel thread le navigateur devrait-il prendre en ce moment? Par conséquent, afin d'éviter la complexité, JavaScript est un seul fil de sa naissance, qui est devenu la caractéristique centrale de cette langue et ne changera pas à l'avenir.
Tâches de file d'attente
Le threading unique signifie que toutes les tâches doivent être en file d'attente et que la tâche précédente sera exécutée avant que la prochaine tâche ne soit exécutée. Si la tâche précédente prend beaucoup de temps, la prochaine tâche doit attendre.
Pilote d'événement asynchrone
De nombreux comportements dans le navigateur sont asynchronisés, tels que: événement de clic de souris, événement de glisser-filet de fenêtre, événement de déclenchement de minuterie, rappel d'achèvement XMLHTTPREQuest, etc. Lorsqu'un événement asynchrone se produit, il entre dans la file d'attente d'événements. Le navigateur dispose d'une boucle de message interne, boucle d'événements, qui interrogera de grandes files d'attente d'événements et des événements de traitement. Par exemple, le navigateur est actuellement occupé à traiter l'événement OnClick, puis un autre événement se produit (tel que Window Onsize), et cet événement asynchrone est mis dans la file d'attente d'événements et attend le traitement. Cet événement ne sera exécuté que lorsque le traitement précédent sera terminé et est gratuit.
Boucle d'événement
JavaScript est unique, mais le navigateur n'est pas unique
Le navigateur aura au moins certains des processus suivants
1. Fil de rendu GUI du navigateur
2. Fil de moteur JavaScript
3. Fil de déclenchement chronométré du navigateur
4. Événement du navigateur déclenche le fil
5. Browser HTTP Asynchronous Request Thread
Parce que le moteur JavaScript est unique, le code est d'abord enfoncé vers la file d'attente, puis exécuté par le moteur de la première manière. Les fonctions de traitement des événements et les fonctions d'exécution du minuteur seront également placées dans cette file d'attente, puis utiliseront une boucle infinie pour extraire en continu les fonctions de la tête de l'équipe à exécuter. Ceci est une boucle d'événement.
En résumé, JS est unique, mais le navigateur est multi-thread. Lorsque vous rencontrez des choses asynchrones, le navigateur mettra le rappel asynchrone dans la boucle de l'événement. Lorsque le fil JS n'est pas occupé, lisez la boucle d'événement.
Principe de la minuterie
Comment utiliser la minuterie
setTimeout (FN, retard)
setInterval (fn, retard)
FN est une fonction ou une chaîne, le retard est le temps de retard, l'unité est des millisecondes
Il y a les choses suivantes à noter
1. Bien que FN puisse être une chaîne, il n'est jamais recommandé de l'utiliser comme ceci.
2. S'il y a cette fonction dans FN, cela pointera vers la fenêtre lors de l'exécution.
Si vous comprenez bien le fil unique et la boucle d'événements, le principe de la minuterie sera facile à comprendre.
Si une minuterie est définie, lorsque le temps de retard est atteint, le navigateur mettra l'événement d'exécution retardé dans la boucle d'événement. Lorsque l'heure est passée, si le fil JS est inactif, il sera exécuté (donc la précision de la minuterie est inexacte)
J'ai lu un article sur la différence entre Settimeout et SetInterval qui interrogent toujours les fonctions. Le code est le suivant
La copie de code est la suivante:
setTimeout (function () {
setTimeout (arguments.callee, 100)
}, 100)
setInterval (function () {}, 1000)
La signification générale de l'article est que Settimeout démarre le minuteur suivant après l'exécution de la fonction de rappel, il doit donc être exécuté à intervalles, tandis que SetInterval est exécuté tout le temps. Si vous rencontrez un fil JS qui continue de s'exécuter, vous pouvez ajouter plusieurs rappels dans la boucle d'événement. Lorsque le thread JS n'est pas occupé, plusieurs exécutions seront exécutées l'une après l'autre.
Après les tests, il a été constaté que SetInterval est à un certain intervalle, peu importe IE, FF, Chrome, Opera et Safari.
Le code de test est le suivant
La copie de code est la suivante:
setInterval (function () {
xx.innerhtml = xx.innerhtml + 1;
}, 100);
pour (var i = 0; i <6000000; i ++) {
xx.offsetwidth
}
setTimeout (function () {
débogueur;
}, 10)
Lorsque les points d'arrêt ne sont toujours imprimés que 1
Problèmes de précision de la minuterie
En raison du fil unique JS, si vous rencontrez l'activité, la minuterie sera certainement inexacte, et ce sera certainement plus long et plus long. Cela semble insoluble, pas de solution.
Un autre problème de précision est l'intervalle minimum setTimeout (Fun, 0)
Lorsque le fil JS n'est pas occupé, il est impossible d'exécuter immédiatement après 0 seconde. Il y a toujours un intervalle minimum et chaque navigateur est toujours différent. Cela n'a pas été testé.
J'ai lu un article sur la norme de W3C. L'exécution de temps minimum de la minuterie est de 4 ms. Il n'y a aucun moyen de vérifier la source si vous ne le trouvez pas! ! !
Quelques optimisations liées aux minuteries
Il y a encore des optimisations lors de la fabrication des minuteries
1. Par exemple, si vous liez la fenêtre.Onresize, le déclencheur sera très fréquent lorsque le navigateur est zoom, vous pouvez donc retarder l'exécution. Lorsque la prochaine exécution sera effacée, elle réduira une exécution fréquente.
Le pseudo-code est le suivant
La copie de code est la suivante:
var temporisateur;
fonction r () {
ClearTimeout (temporisateur);
timer = setTimeout (function () {
// faire quelque chose
}, 150);
}
2. Lorsque la barre de défilement est abaissée, c'est aussi un peu. Par exemple, le chargement paresseux de l'image devrait également avoir une minuterie pour éviter des calculs excessifs.
3. Lorsqu'il y a plusieurs endroits où les minuteries sont nécessaires, vous pouvez les fusionner dans une minuterie. L'intervalle de temps est le plus petit. Ensuite, la fonction de rappel qui doit être exécutée est fourrée dans le tableau. Lorsque l'intervalle de temps est atteint, parcourez le tableau à exécuter.
Une petite démo
La copie de code est la suivante:
<! Doctype html>
<html>
<adal>
<meta charset = "utf-8" />
<style>
.Wrap {largeur: 80%; marge: 30px automatique; Border: 1px solide #ccc; rembourrage: 20px;}
.c {Border: 1Px solide #ccc; hauteur: 30px; marge-fond: 20px;}
</ style>
</ head>
<body>
<div id = "xx"> </div>
<div>
<div id = "a1"> 0 </div>
<div id = "a2"> 0 </div>
<div id = "a3"> 0 </div>
<div id = "a4"> 0 </div>
</div>
<script src = "http://static.paipaiimg.com/paipai_h5/js/ttj/zepto.min.js"> </cript>
<script type = "text / javascript">
var runtime = {
Options: {
Étape: 1000
},
rappels: [],
addCallbacks: [],
Démarrer: faux,
minuterie: null,
extension: function () {
var cible = arguments [0] || {}, i = 1, longueur = arguments.length, options;
if (typeof Target! = "objet" && type de cible! = "fonction")
Target = {};
pour (; i <durée; i ++)
if ((options = arguments [i])! = null)
pour (nom var dans les options) {
var copy = options [nom];
if (cible === copie)
continuer;
si (copie! == Undefined)
Target [name] = copy;
}
cible de retour;
},
init: fonction (options) {
$ .Extend (this, this.options, options || {});
},
Ajouter: fonction (plaisir, options) {
Options = Options || {};
this.addcallbacks.push ({
Amusant: amusant,
starttime: new Date (). gettime (),
Étape: options.step || this.strep,
I: 1
});
var self = this;
if (! this.start) {
this.callbacks = [fun];
this.start = true;
this.startTime = new Date (). GetTime ();
this.timer = setInterval (function () {
self.done ();
}, this.step);
}
},
fait: function () {
var callbacks = this.Callbacks,
self = ceci,
newarr = [];
$ .each (rappel, fonction (i, obj) {
if (obj.step == self.step) {
obj.fun ();
}autre{
if (obj.i == obj.step / self.step) {
if ((new Date (). getTime ()) - obj.starttime> obj.step * 2/3) {
obj.fun ();
}
obj.i = 1;
}autre{
obj.i = obj.i + 1;
}
}
});
$ .each (this.addcallbacks, fonction (i, obj) {
if (obj.step == self.step) {
if ((new Date (). getTime ()) - obj.starttime> obj.step * 2/3) {
obj.fun ();
callbacks.push (obj);
}autre{
Newarr.push (obj);
}
}autre{
obj.i = obj.i + 1;
callbacks.push (obj);
}
});
this.addcallbacks = newarr;
},
Clear: function () {
ClearInterval (this.timer);
}
}
runtime.init ();
runtime.add (function () {
a1.innerhtml = ~~ a1.innerhtml + 1;
});
runtime.add (function () {
a2.innerhtml = ~~ a2.innerhtml + 1;
}, {étape: 2000});
runtime.add (function () {
a3.innerhtml = ~~ a3.innerhtml + 1;
}, {étape: 4000});
runtime.add (function () {
a4.innerhtml = ~~ a4.innerhtml + 1;
}, {étape: 8000});
</cript>
</docy>
</html>
Avez-vous une idée de la minuterie JavaScript? Laissez-moi un message si vous avez des questions.