Wat is precies een Node.js-gebeurtenislus-vinkje?

Ik ben me meer gaan verdiepen in de binnenkant van de Node.js-architectuur, en een term die ik veel zie opduiken is “tick” zoals in “volgende tick of the event loop” of de functie nextTick().

Wat ik niet heb gezien, is een solide definitie van wat een ‘vinkje’ precies is. Op basis van verschillende artikelen (zoals deze), heb ik een concept samen in mijn hoofd, maar ik weet niet zeker hoe nauwkeurig het is.

Kan ik een nauwkeurige en gedetailleerde beschrijving krijgen van een Node.js-gebeurtenislus-vinkje?


Antwoord 1, autoriteit 100%

Onthoud dat hoewel JavaScript single-threaded is, alle I/O van nodes en oproepen naar native API’s ofwel asynchroon zijn (met platformspecifieke mechanismen) of op een aparte thread worden uitgevoerd. (Dit wordt allemaal afgehandeld via libuv.)

Dus wanneer er gegevens beschikbaar zijn op een socket of een native API-functie is teruggekeerd, hebben we een gesynchroniseerde manier nodig om de JavaScript-functie aan te roepen die geïnteresseerd is in de specifieke gebeurtenis die zojuist heeft plaatsgevonden.

Het is niet veilig om de JS-functie gewoon aan te roepen vanuit de thread waar de native gebeurtenis plaatsvond om dezelfde redenen die je zou tegenkomen in een gewone multi-threaded applicatie: race-omstandigheden, niet-atomaire geheugentoegang, enzovoort.

Dus wat we doen, is de gebeurtenis op een threadveilige manier in een wachtrij plaatsen. In te vereenvoudigde psuedocode, zoiets als:

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

Vervolgens, terug naar de belangrijkste JavaScript thread(maar aan de C-kant van de dingen), doen we zoiets als:

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
}

De while (true)(die niet echt bestaat in de broncode van het knooppunt; dit is puur illustratief) vertegenwoordigt de gebeurtenislus. De binnenste forroept de JS-functie op voor elke gebeurtenis die in de wachtrij stond.

Dit is een vinkje: de synchrone aanroep van nul of meer callback-functies in verband met externe gebeurtenissen. Zodra de wachtrij is leeggemaakt en de laatste functie terugkeert, is het vinkje voorbij. We gaan terug naar het begin (het volgende vinkje) en controleren op gebeurtenissen die vanuit andere threads aan de wachtrij zijn toegevoegd terwijl onze JavaScript actief was.

Wat kan dingen aan de wachtrij toevoegen?

  • process.nextTick
  • setTimeout/setInterval
  • I/O (dingen van fs, net, enzovoort)
  • crypto‘s processorintensieve functies zoals cryptostreams, pbkdf2 en de PRNG (die eigenlijk een voorbeeld zijn van…)
  • alle native modules die de libuv-werkwachtrijgebruiken om synchrone C/C++ te maken bibliotheekoproepen zien er asynchroon uit

Antwoord 2, autoriteit 8%

Een eenvoudiger antwoord voor degenen die nieuw zijn in JavaScript:

Het eerste dat u moet begrijpen, is dat JavaScript een “single-threaded-omgeving” is. Dit verwijst naar het gedrag van JavaScript om uw codeblokken één voor één uit “de gebeurtenislus” op een enkele thread uit te voeren. Hieronder is een rudimentaire implementatie van de gebeurtenislus uit Kyle Simpson’s boek ydkJS en daarna een uitleg:

// `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);
        }
    }
}

De eerste while-lus simuleert de gebeurtenislus. Een vinkje is het verwijderen van een evenement uit de “event loop-wachtrij” en het uitvoeren van dat evenement.

Zie de reactie van ‘Josh3796’ voor een meer gedetailleerde uitleg van wat er gebeurt bij het uit de wachtrij halen en uitvoeren van een evenement.

Ik raad ook aan om het boek van Kyle Simpson te lezen voor diegenen die geïnteresseerd zijn in een diepgaand begrip van JavaScript. Het is volledig gratis en open-source en kan worden gevonden via deze link:
https://github.com/getify/You-Dont-Know-JS

Het specifieke gedeelte waarnaar ik verwees, is hier te vinden: https://github.com/getify/You-Dont-Know-JS/blob/2nd-ed/sync-async/ch1.md


Antwoord 3

Zeer eenvoudige en korte manier van Event Loop-tick is:

Het wordt gebruikt door het interne mechanisme van het knooppunt waarbij wanneer een reeks verzoeken in een wachtrij wordt verwerkt, het vinkje wordt gestart dat de voltooiing van een taak vertegenwoordigt


Antwoord 4

Een “vinkje” verwijst naar een volledige passage door de gebeurtenislus. Verwarrend genoeg neemt setImmediate() een vinkje om uit te voeren, terwijl process.nextTick() directer is, dus de twee functies verdienen een naamswisseling.

Other episodes