Heim  >  Artikel  >  Web-Frontend  >  Vertieftes Verständnis des JavaScript-Ausführungsmechanismus

Vertieftes Verständnis des JavaScript-Ausführungsmechanismus

不言
不言Original
2018-08-31 10:12:23973Durchsuche

Der Inhalt dieses Artikels befasst sich mit einem umfassenden Verständnis des JavaScript-Ausführungsmechanismus. Er hat einen gewissen Referenzwert. Ich hoffe, dass er für Sie hilfreich ist.

Zuallererst wissen wir alle, dass JavaScript eine Single-Threaded-Sprache ist, daher können wir schlussfolgern:

JavaScript wird in der Reihenfolge der Anweisungen ausgeführt

Erster Blick:

let a = '1'
console.log(a)

let b = '2'
console.log(b)

Natürlich kennt jeder das Ergebnis, das 1, 2 nacheinander ausgibt

Allerdings auch anders:

setTimeout(function() {
    console.log(1)
})

new Promise(function(resolve) {
    console.log(2)
    for(var i = 0;i< 10;i++){
        i === 10 && resolve()
    }
}).then(function() {
    console.log(3)
})
console.log(4)

Sehen Sie sich zu diesem Zeitpunkt die sequentielle Ausführung des Codes an, Ausgabe 1, 2, 3, 4. Okay, lege es in den Browser und führe es aus, was? Die Ausgabe ist tatsächlich 2, 4, 3, 1. Wie wäre es, sie in der versprochenen Reihenfolge auszuführen? Als nächstes müssen wir den Ausführungsmechanismus von JavaScript verstehen.

Single-Threaded

Zuallererst ist JavaScript eine Single-Thread-Sprache. Beim neuesten HTML5-Start von Web-Worker hat sich der Kern, dass JavaScript eine Single-Thread-Sprache ist, nicht geändert . Daher wird JavaScript-Multithreading basierend auf einem einzelnen Thread simuliert. Bedenken Sie also, dass JavaScript eine Single-Threaded-Sprache ist.

Ereignisschleife

Aufgaben sind in zwei Kategorien unterteilt:

  • Synchrone Aufgaben

  • Asynchrone Aufgaben

Wenn wir die Seite öffnen, ist das Rendern der Seite eine Menge synchroner Aufgaben, und die zeitaufwändigen Aufgaben wie das Laden von Bildern und Audioressourcen sind asynchrone Aufgaben. Der Hauptinhalt der Zeitschleife ist:

  1. Wenn eine Aufgabe in den Ausführungsstapel gelangt, bestimmen Sie, ob es sich um eine synchrone Aufgabe oder eine asynchrone Aufgabe handelt Führen Sie den Hauptthread aus und geben Sie die Funktion „Ereignistabelle asynchron“ ein.

  2. Wenn das angegebene Ereignis abgeschlossen ist, verschiebt die Ereignistabelle diese Funktion in die Ereigniswarteschlange

  3. Nachdem die Aufgabe im Hauptthread abgeschlossen ist , go Die Aufgabenwarteschlange liest die entsprechende Funktion und tritt in den Hauptthread ein, um sie auszuführen

  4. Der obige Vorgang wird kontinuierlich wiederholt, was eine Ereignisschleife bildet

unter denen js Die Engine verfügt über einen Überwachungsprozess, der ständig prüft, ob der Haupt-Thread-Ausführungsstapel leer ist. Sobald er leer ist, geht er in die Zeitwarteschlange, um zu prüfen, ob Funktionen auf den Aufruf warten.

Zum Beispiel:

setTimeout( function() {
    console.log(1)
}, 0)
console.log(2)
  • Zuerst setTimeout und die Ereignistabelle eingeben

  • Konsole.log(2) ausführen

  • Die von setTimeout ausgeführte Funktion gelangt in die Ereigniswarteschlange

  • Der Hauptthread liest die Funktionsausführung aus der Ereigniswarteschlange

Aus diesem Grund wird die Funktion nicht sofort ausgeführt, selbst wenn setTimeout(fn, 0) gesetzt ist. Selbst wenn der Hauptthread leer ist, können 0 ms nicht erreicht werden. Gemäß dem HTML-Standard beträgt das Minimum 4 ms.

setInterval

hat auch eine ähnliche Funktion wie setTimeout, die für setInterval in einer Schleife ausgeführt wird. Bezüglich der Ausführungsreihenfolge platziert setInterval die registrierte Funktion in bestimmten Abständen in der Ereigniswarteschlange. Wenn die vorherige Aufgabe zu lange dauert, müssen Sie ebenfalls warten.

Beachten Sie jedoch, dass setInterval(fn, ms) nicht jedes Mal ausgeführt wird, wenn ms ausgeführt wird, sondern jedes Mal, wenn ms ausgeführt wird, fn in die Aufgabenwarteschlange aufgenommen wird. Das heißt, wenn das Ausführungsereignis der Rückruffunktion von setInterval die Verzögerung ms überschreitet, ist das Ereignisintervall nicht sichtbar.

Promise und process.nextTick(callback)

Neben verallgemeinerten synchronen Aufgaben und asynchronen Aufgaben gibt es auch detailliertere Aufteilungen von Aufgaben, die unterteilt sind in:

  • Makroaufgabe (Makroaufgabe): einschließlich des gesamten Codeskripts, setTimeout, setInterval

  • Mikroaufgabe (Mikroaufgabe): Promise, process.nextTick

Die Reihenfolge der Ereignisschleife bestimmt die Ausführungsreihenfolge des JS-Codes. Nach Eingabe des Gesamtcodes (Makrotask) startet der erste Zyklus. Führen Sie dann alle Mikrotasks aus. Beginnen Sie dann erneut mit der Makroaufgabe, suchen Sie eine der auszuführenden Aufgabenwarteschlangen und führen Sie dann alle Mikroaufgaben aus.

Verwenden Sie einen Code zur Veranschaulichung:

setTimeout(function() {
    console.log('1');
})

new Promise(function(resolve) {
    console.log('2');
    resolve()
}).then(function() {
    console.log('3');
})

console.log('4');
  • Dieser Code wird als Makroaufgabe verwendet, um den ersten Zyklus zu starten

  • Zuerst, wenn setTimeout angetroffen wird, dann tritt seine Rückruffunktion in die Ereigniswarteschlange der Makroaufgabe ein

  • Wenn Promise angetroffen wird, wird Promise sofort ausgeführt, gibt 2 aus und Die then Aufgabe wird eingegeben. Gehen Sie zur Mikrotask-Ereigniswarteschlange.

  • Die Konsole wird unten angetroffen und gibt 4 aus.

  • Die erste Makroaufgabe endet , schauen Sie sich die Mikrotask-Ereigniswarteschlange an, Ausführen then, Ausgabe 3

  • Die erste Runde der Schleife endet, sehen Sie sich die Ausführung der Rückruffunktion setTimeout in der Makrotask-Warteschlange an, Ausgabe 1

  • Alle Ergebnisse sind: 2, 4, 3, 1

Nachdem wir die Grundprinzipien verstanden haben, schauen wir uns ein komplizierteres an:

console.log('1');

setTimeout(function() {
    console.log('2');
    process.nextTick(function() {
        console.log('3');
    })
    new Promise(function(resolve) {
        console.log('4');
        resolve();
    }).then(function() {
        console.log('5')
    })
})
process.nextTick(function() {
    console.log('6');
})
new Promise(function(resolve) {
    console.log('7');
    resolve();
}).then(function() {
    console.log('8')
})

setTimeout(function() {
    console.log('9');
    process.nextTick(function() {
        console.log('10');
    })
    new Promise(function(resolve) {
        console.log('11');
        resolve();
    }).then(function() {
        console.log('12')
    })
})

Weiß nicht. Was ist deine Antwort? Als nächstes analysieren wir es:

Erste Runde:

  1. Zuerst geht der gesamte Code als Makroaufgabe in den Hauptthread ein und trifft zunächst auf console.log()Ausgabe 1

  2. Begegnen Sie dem ersten setTimeout() und betreten Sie die Makroaufgabenwarteschlange

  3. Betreten Sie den ersten Process.nextTick() und betreten Sie die Mikroaufgabenwarteschlange

  4. trifft dann auf Promise, wird sofort ausgeführt, gibt 7 aus und then wird zur Mikrotask-Warteschlange hinzugefügt

  5. trifft auf das zweite setTimeout, Geben Sie die Makroaufgabenwarteschlange ein

  6. und führen Sie dann zwei Mikroaufgaben aus

  7. ausführen Process.nextTick()Ausgabe 6

  8. Ausführenthen, Ausgabe 8

Auf diese Weise ist die erste Runde der Schleife vollständig beendet und die zweite Runde der Ereignisschleife wird ausgeführt, also die erste setTimeout

  1. erste Begegnungen console.log(), gibt 2

  2. Begegnungen Process.nextTick() aus, tritt in die Mikrotask-Warteschlange ein

  3. Wenn Sie auf Promise stoßen, führen Sie sofort Ausgabe 4 aus, then geben Sie die Mikrotask-Warteschlange ein

  4. und führen Sie dann die erste Mikrotask aus, Ausgabe 3

  5. Dann ausführen, 5 ausgeben

Auf diese Weise ist die zweite Runde der Ereignisschleife beendet und schließlich wird das zweite setTimeout und das zweite ähnelt dem oben genannten Prinzip, daher werde ich die Erklärung nicht wiederholen. Das Endergebnis ist also: setTimeout1,7,6,8,2,4,3,5,9,11,10,12

Verwandte Empfehlungen:

Detaillierte Erläuterung von Beispielen für js-Ausführungsmechanismen

JavaScript Laufmechanismus Ereignisschleife

Das obige ist der detaillierte Inhalt vonVertieftes Verständnis des JavaScript-Ausführungsmechanismus. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn