Was genau ist ein Node.js-Ereignisschleifen-Tick?


83

Ich habe mich mehr mit den Interna der Node.js-Architektur befasst, und ein Begriff, den ich häufig sehe, ist "tick" wie in "next tick of the event loop" oder der Funktion nextTick () .

Was ich nicht gesehen habe, ist eine solide Definition dessen, was genau ein "Tick" ist. Basierend auf verschiedenen Artikeln ( wie diesem ) konnte ich ein Konzept in meinem Kopf zusammensetzen, bin mir aber nicht sicher, wie genau es ist.

Kann ich eine genaue und detaillierte Beschreibung eines Node.js-Ereignisschleifen-Ticks erhalten?


Da es sich um eine "Schleife" handelt, bedeutet dies "das nächste Mal, wenn eine Schleife ausgeführt wird". Ein Häkchen ist also eine ganze Schleife. Es endet, wenn keine Ereignisse ausgelöst werden und nodejs alle Schleifen durchlaufen hat, um zu überprüfen, ob eines ausgelöst wird. "nextTick" bedeutet das nächste Schleife nach der aktuellen.
Gntem

Antworten:


155

Denken Sie daran, dass während JavaScript Single-Threaded ist, alle E / A und Aufrufe des Knotens an native APIs entweder asynchron sind (mithilfe plattformspezifischer Mechanismen) oder auf einem separaten Thread ausgeführt werden. (Dies wird alles über libuv erledigt.)

Wenn also Daten auf einem Socket verfügbar sind oder eine native API-Funktion zurückgegeben wurde, benötigen wir eine synchronisierte Methode, um die JavaScript-Funktion aufzurufen, die an dem gerade aufgetretenen Ereignis interessiert ist.

Es ist nicht sicher, die JS-Funktion einfach von dem Thread aus aufzurufen, in dem das native Ereignis aufgetreten ist, und zwar aus denselben Gründen, die in einer regulären Multithread-Anwendung auftreten würden - Race-Bedingungen, nicht-atomarer Speicherzugriff usw.

Wir stellen das Ereignis also threadsicher in eine Warteschlange. Im vereinfachten Pseudocode so etwas wie:

lock (queue) {
    queue.push(event);
}

Dann, zurück zum Haupt-JavaScript- Thread (aber auf der C-Seite der Dinge), machen wir so etwas wie:

while (true) {
    // this is the beginning of a tick

    lock (queue) {
        var tickEvents = copy(queue); // copy the current queue items into thread-local memory
        queue.empty(); // ..and empty out the shared queue
    }

    for (var i = 0; i < tickEvents.length; i++) {
        InvokeJSFunction(tickEvents[i]);
    }

    // this the end of the tick
}

Das while (true)(das im Quellcode des Knotens nicht vorhanden ist; dies ist nur zur Veranschaulichung) repräsentiert die Ereignisschleife . Das Innere forruft die JS-Funktion für jedes Ereignis auf, das sich in der Warteschlange befand.

Dies ist ein Häkchen: der synchrone Aufruf von null oder mehr Rückruffunktionen, die externen Ereignissen zugeordnet sind. Sobald die Warteschlange geleert ist und die letzte Funktion zurückkehrt, ist das Häkchen beendet. Wir kehren zum Anfang (dem nächsten Häkchen) zurück und suchen nach Ereignissen, die von anderen Threads zur Warteschlange hinzugefügt wurden, während unser JavaScript ausgeführt wurde .

Was kann der Warteschlange etwas hinzufügen?

  • process.nextTick
  • setTimeout/.setInterval
  • I / O (Stoff , aus fs, netund so weiter)
  • cryptoDie prozessorintensiven Funktionen von Crypto Streams, pbkdf2 und PRNG (die eigentlich ein Beispiel für ... sind)
  • Alle nativen Module, die die libuv-Arbeitswarteschlange verwenden , um synchrone C / C ++ - Bibliotheksaufrufe asynchron aussehen zu lassen

2
Ja, du hast es geschafft. Das Kopieren der Warteschlange und das Durchlaufen aller Ereignisse auf der Kopie war das, worüber ich mich speziell wunderte. Macht jetzt aber sehr viel Sinn. Vielen Dank.
d512

Ist dies das berühmte "Asynchrone Iterationsmuster" -Algo?
Stef

1
@sanjeev, was meinst du mit "regulärer Job"? Eine laufende JavaScript-Anwendung verarbeitet nur Ereignisse.
Josh3736

2
Ich möchte hinzufügen, dass in 0.10.x setImmediateauch eine Funktion in die Warteschlange gestellt wird.
Daniel Khan

1
Bedeutet Tick Ereignisschleifenphase?
Faressoft

10

Eine einfachere Antwort für diejenigen, die neu in JavaScript sind:

Das erste, was zu verstehen ist, ist, dass JavaScript eine "Single-Threaded-Umgebung" ist. Dies bezieht sich auf das Verhalten von JavaScript, Ihre Codeblöcke einzeln aus der "Ereignisschleife" in einem einzelnen Thread auszuführen. Unten finden Sie eine rudimentäre Implementierung der Ereignisschleife aus Kyle Simpsons Buch ydkJS und anschließend eine Erklärung:

// `eventLoop` is an array that acts as a queue (first-in, first-out)
var eventLoop = [ ];
var event;

// keep going "forever"
while (true) {
    // perform a "tick"
    if (eventLoop.length > 0) {
        // get the next event in the queue
        event = eventLoop.shift();

        // now, execute the next event
        try {
            event();
        }
        catch (err) {
            reportError(err);
        }
    }
}

Die erste while-Schleife simuliert die Ereignisschleife. Ein Häkchen ist das Ausreihen eines Ereignisses aus der "Ereignisschleifenwarteschlange" und die Ausführung dieses Ereignisses.

In der Antwort von 'Josh3796' finden Sie eine detailliertere Erläuterung der Ereignisse beim Ausreihen und Ausführen eines Ereignisses.

Außerdem empfehle ich Kyle Simpsons Buch für diejenigen, die ein tiefes Verständnis von JavaScript haben möchten. Es ist völlig kostenlos und Open Source und kann unter folgendem Link gefunden werden: https://github.com/getify/You-Dont-Know-JS

Den spezifischen Abschnitt, auf den ich verwiesen habe, finden Sie hier: https://github.com/getify/You-Dont-Know-JS/blob/2nd-ed/sync-async/ch1.md


1

Sehr einfache und kurze Art der Ereignisschleife ist:

Es wird vom knoteninternen Mechanismus verwendet, bei dem bei der Verarbeitung von Anforderungen in einer Warteschlange ein Häkchen ausgelöst wird, das den Abschluss einer Aufgabe darstellt


Können Sie bitte eine Quelle für Ihre Antwort angeben?
Kick Buttowski
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.