JavaScript Single Thread
Das einzelne Threading von JavaScript hängt mit seinem Zweck zusammen. Als Browser -Skriptsprache besteht der Hauptzweck von JavaScript darin, mit Benutzern zu interagieren und DOM zu betreiben. Dies stellt fest, dass es nur ein einzelnes Gewinde sein kann, andernfalls verursacht es sehr komplexe Synchronisationsprobleme. Angenommen, JavaScript hat zwei Threads gleichzeitig, ein Thread fügt einen Inhalt eines bestimmten DOM -Knotens hinzu, und der andere Thread löscht diesen Knoten. Welchen Thread sollte der Browser zu diesem Zeitpunkt aufnehmen? Um Komplexität zu vermeiden, ist JavaScript daher ein einzelner Thread von seiner Geburt, der zum Kernmerkmal dieser Sprache geworden ist und sich in Zukunft nicht ändern wird.
Warteschlangenaufgaben
Ein einzelnes Threading bedeutet, dass alle Aufgaben in die Warteschlange gestellt werden müssen, und die vorherige Aufgabe wird ausgeführt, bevor die nächste Aufgabe ausgeführt wird. Wenn die vorherige Aufgabe lange dauert, muss die nächste Aufgabe warten.
Asynchroner Ereignisfahrer
Viele Verhaltensweisen im Browser sind asynchronisiert, wie z. Der Browser verfügt über eine interne große Nachrichtenschleife und eine Ereignisschleife, die große Ereigniswarteschlangen und Prozessereignisse abfragt. Zum Beispiel ist der Browser derzeit damit beschäftigt, das Onclick -Ereignis zu verarbeiten, und dann tritt ein weiteres Ereignis auf (z. B. das Fenster in der Größenordnung), und dieses asynchrone Ereignis wird in die Ereigniswarteschlange gestellt und wartet auf die Verarbeitung. Diese Veranstaltung wird nur ausgeführt, wenn die vorherige Verarbeitung abgeschlossen ist und kostenlos ist.
Ereignisschleife
JavaScript ist Single-Threaded, aber der Browser ist nicht Single-Thread
Der Browser wird zumindest einige der folgenden Prozesse haben
1. Browser -GUI -Rendering -Thread
2. JavaScript Engine -Thread
3. Browser Timed Trigger -Thread
4. Browserereignis Trigger -Thread
5. Browser HTTP Asynchronous Request -Thread
Da die JavaScript-Engine Single-Threaded ist, wird der Code zuerst in die Warteschlange gedrückt und dann zuerst von der Engine ausgeführt. Die Funktionen zur Ausführung von Ereignissen und Timer -Ausführungsfunktionen werden ebenfalls in dieser Warteschlange platziert und verwenden dann eine unendliche Schleife, um die Funktionen aus dem Leiter des Teams zur Ausführung kontinuierlich zu extrahieren. Dies ist Ereignisschleife.
Zusammenfassend ist JS Single-Threaded, aber der Browser ist multi-threaded. Bei der Begegnung mit asynchronen Dingen steckt der Browser den asynchronen Rückruf in die Ereignisschleife. Wenn der JS -Thread nicht beschäftigt ist, lesen Sie die Ereignisschleife.
Timerprinzip
So verwenden Sie den Timer
setTimeout (FN, Verzögerung)
setInterval (FN, Verzögerung)
FN ist eine Funktion oder eine String, Verzögerung ist die Zeit der Verzögerung, die Einheit ist Millisekunden
Es gibt die folgenden Dinge zu beachten
1. Obwohl FN eine Zeichenfolge sein kann, wird es nie empfohlen, sie so zu verwenden.
2. Wenn es diese Funktion in FN gibt, zeigt dies beim Ausführen auf das Fenster.
Wenn Sie JS Single Thread und Event Loop gut verstehen, ist das Prinzip des Timers leicht zu verstehen.
Wenn ein Timer festgelegt ist, stellt der Browser, wenn die Verzögerungszeit erreicht ist, das verzögerte Ausführungsereignis in die Ereignisschleife. Wenn die Zeit abgelaufen ist und der JS -Thread im Leerlauf ist, wird er ausgeführt (so dass die Genauigkeit des Timers ungenau ist)
Ich habe einen Artikel über den Unterschied zwischen SetTimeout und SetInterval gelesen, der immer Funktionen befragt hat. Der Code ist wie folgt
Die Codekopie lautet wie folgt:
setTimeout (function () {
setTimeout (Argumente.Callee, 100)
}, 100)
setInterval (function () {}, 1000)
Die allgemeine Bedeutung des Artikels ist, dass SetTimeOut den nächsten Timer nach Ausführung der Rückruffunktion startet, sodass er in Intervallen ausgeführt werden muss, während SetInterval ständig ausgeführt wird. Wenn Sie auf einen JS -Thread stoßen, der weiter ausführt, können Sie in der Ereignisschleife mehrere Rückrufe hinzufügen. Wenn der JS -Thread nicht beschäftigt ist, werden nacheinander mehrere Ausführungen ausgeführt.
Nach dem Testen wurde festgestellt, dass SetInterval in einem bestimmten Abstieg ist, egal unter IE, FF, Chrome, Opera und Safari.
Der Testcode ist wie folgt
Die Codekopie lautet wie folgt:
setInterval (function () {
xx.innerhtml = xx.innerhtml+1;
}, 100);
für (var i = 0; i <6000000; i ++) {
xx.offsetwidth
}
setTimeout (function () {
Debugger;
}, 10)
Wenn Haltepunkte noch nur 1 gedruckt sind
Timergenauigkeitsprobleme
Aufgrund von JS Single Thread wird der Timer auf jeden Fall ungenau sein, und es wird definitiv immer länger. Dies scheint unlösbar zu sein, keine Lösung.
Ein weiteres Genauigkeitsproblem ist das Mindestintervall -SetTimeout (Spaß, 0)
Wenn der JS -Thread nicht beschäftigt ist, ist es unmöglich, unmittelbar nach 0 Sekunden auszuführen. Es gibt immer ein Mindestintervall, und jeder Browser ist immer noch anders. Dies wurde nicht getestet.
Ich habe einen Artikel über den Standard von W3C gelesen. Die minimale Zeitausführung des Timers beträgt 4 ms. Es gibt keine Möglichkeit, die Quelle zu überprüfen, wenn Sie sie nicht finden können! ! !
Einige Optimierungen im Zusammenhang mit Timern
Es gibt noch einige Optimierungen bei der Herstellung von Timern
1. Wenn Sie beispielsweise ein Fenster binden. Wenn die nächste Ausführung gelöscht wird, verringert sie die häufige Ausführung.
Der Pseudo-Code ist wie folgt
Die Codekopie lautet wie folgt:
var Timer;
Funktion r () {
Clearimeout (Timer);
timer = setTimeout (function () {
// etwas mach
}, 150);
}
2. Wenn die Bildlaufleiste heruntergezogen wird, ist sie auch ein bisschen. Zum Beispiel sollte die Ladung des Bildes auch einen Timer haben, um übermäßige Berechnungen zu vermeiden.
3. Wenn es mehrere Orte gibt, an denen Timer benötigt werden, können Sie sie in einen Timer verschmelzen. Das Zeitintervall ist das kleinste. Dann wird die Rückruffunktion, die ausgeführt werden muss, in das Array gestopft. Wenn das Zeitintervall erreicht ist, iterieren Sie durch das Array, um auszuführen.
Eine kleine Demo
Die Codekopie lautet wie folgt:
<! DocType html>
<html>
<kopf>
<meta charset = "utf-8" />
<Styles>
.Wrap {Breite: 80%; Rand: 30px Auto; Grenze: 1PX Solid #CCC; Polsterung: 20px;}
.C {Border: 1px solide #CCC; Höhe: 30px; Margin-Bottom: 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"> </script>
<script type = "text/javaScript">
var runtime = {
Optionen: {
Schritt: 1000
},
Rückrufe: [],
AddCallbacks: [],
Start: Falsch,
Timer: null,
Erweitern Sie: function () {
var target = argumente [0] || {}, i = 1, Länge = Argumente.length, Optionen;
if (typeof target! = "object" && typeof target! = "function")
target = {};
für (; i <länge; i ++)
if ((Optionen = Argumente [i])! = NULL)
für (var name in Optionen) {
var Copy = Optionen [Name];
if (Ziel === Kopie)
weitermachen;
if (kopieren! == undefiniert)
Ziel [Name] = Kopie;
}
Ziel zurückgeben;
},
Init: Funktion (Optionen) {
$ .extend (this, this.options, Optionen || {});
},
Hinzufügen: Funktion (Spaß, Optionen) {
Optionen = Optionen || {};
this.addcallbacks.push ({{
Spaß: Spaß,
STARTTIME: NEUE DATE (). GETTIME (),
Schritt: Optionen.step || this.step,
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);
}
},
Fertig: function () {
var callbacks = this.callbacks,
self = this,
newarr = [];
$ .each (Rückrufe, Funktion (i, obj) {
if (obj.step == self.step) {
obj.fun ();
}anders{
if (obj.i == obj.step/self.step) {
if ((neues Datum ().
obj.fun ();
}
obj.i = 1;
}anders{
obj.i = obj.i + 1;
}
}
});
$ .each (this.addcallbacks, function (i, obj) {
if (obj.step == self.step) {
if ((neues Datum ().
obj.fun ();
callbacks.push (obj);
}anders{
newarr.push (obj);
}
}anders{
obj.i = obj.i + 1;
callbacks.push (obj);
}
});
this.addcallbacks = newarr;
},
klare: function () {
ClearInterval (this.timer);
}
}
runtime.init ();
runtime.add (function () {
A1.InnerHtml = ~~ A1.InnerHtml+1;
});
runtime.add (function () {
a2.InnerHtml = ~~ a2.innerhtml+1;
}, {Schritt: 2000});
runtime.add (function () {
A3.ernnerHtml = ~~ A3.InnerHtml+1;
}, {Schritt: 4000});
runtime.add (function () {
A4.InnerHtml = ~~ A4.InnerHtml+1;
}, {Schritt: 8000});
</script>
</body>
</html>
Haben Sie eine Vorstellung vom JavaScript -Timer? Hinterlassen Sie mir eine Nachricht, wenn Sie Fragen haben.