Model provádění JavaScriptu je nuancovaný a snadno nepochopitelný. Pomoci vám může znalost smyčky událostí v jejím jádru.
JavaScript je jednovláknový jazyk vytvořený tak, aby zpracovával úkoly jeden po druhém. Smyčka událostí však umožňuje JavaScriptu zpracovávat události a zpětná volání asynchronně emulací simultánních programovacích systémů. To zajišťuje výkon vašich aplikací JavaScript.
Co je smyčka událostí JavaScriptu?
Smyčka událostí JavaScriptu je mechanismus, který běží na pozadí každé JavaScriptové aplikace. Umožňuje JavaScriptu zpracovávat úkoly v pořadí, aniž by blokoval jeho hlavní prováděcí vlákno. Toto je označováno jako asynchronní programování.
Smyčka událostí udržuje frontu úloh ke spuštění a přivádí tyto úlohy doprava webové rozhraní API pro provedení jeden po druhém. JavaScript sleduje tyto úkoly a zpracovává každý podle úrovně složitosti úkolu.
Abychom pochopili potřebu smyčky událostí JavaScriptu a asynchronního programování. Musíte pochopit, jaký problém to v podstatě řeší.
Vezměte si například tento kód:
functionlongRunningFunction() {
// This function does something that takes a long time to execute.
for (var i = 0; i < 100000; i++) {
console.log("Hello")
}
}functionshortRunningFunction(a) {
return a * 2 ;
}functionmain() {
var startTime = Date.now();
longRunningFunction();
var endTime = Date.now();// Prints the amount of time it took to execute functions
console.log(shortRunningFunction(2));
console.log("Time taken: " + (endTime - startTime) + " milliseconds");
}
main();
Tento kód nejprve definuje funkci nazývanou longRunningFunction(). Tato funkce provede nějaký složitý a časově náročný úkol. V tomto případě provádí a pro opakování smyčky více než 100 000krát. Tohle znamená tamto console.log("Ahoj") běží 100 000krát.
V závislosti na rychlosti počítače to může trvat dlouho a zablokovat se shortRunningFunction() od okamžitého provedení až do dokončení předchozí funkce.
Pro kontext je zde srovnání času potřebného ke spuštění obou funkcí:
A pak singl shortRunningFunction():
Rozdíl mezi 2 351 milisekundovou operací a 0 milisekundovou operací je zřejmý, když se snažíte vytvořit výkonnou aplikaci.
Jak smyčka událostí pomáhá s výkonem aplikace
Smyčka událostí má různé fáze a části, které přispívají k fungování systému.
Zásobník hovorů
Zásobník volání JavaScriptu je nezbytný pro to, jak JavaScript zpracovává volání funkcí a událostí z vaší aplikace. JavaScript kód se kompiluje shora dolů. Node.js však při čtení kódu přiřadí volání funkcí zdola nahoru. Při čtení vkládá definované funkce jako rámce do zásobníku volání jeden po druhém.
Zásobník volání je zodpovědný za udržování kontextu provádění a správného pořadí funkcí. Dělá to tak, že funguje jako zásobník Last-In-First-Out (LIFO).
To znamená, že poslední funkční rámec, který váš program vloží do zásobníku volání, bude prvním, který zásobník vyskočí a spustí se. To zajistí, že JavaScript zachová správné pořadí provádění funkcí.
JavaScript vytáhne každý snímek ze zásobníku, dokud nebude prázdný, což znamená, že všechny funkce skončily.
Libuv Web API
Jádrem asynchronních programů JavaScriptu je libuv. Knihovna libuv je napsána v programovacím jazyce C, který může komunikovat s operačním systémem nízkoúrovňová rozhraní API. Knihovna bude poskytovat několik rozhraní API, která umožňují spouštění kódu JavaScript paralelně s jinými kód. API pro vytváření vláken, API pro komunikaci mezi vlákny a API pro správu synchronizace vláken.
Například když používáte setTimeout v Node.js pro pozastavení provádění. Časovač se nastavuje pomocí libuv, který řídí smyčku událostí tak, aby po uplynutí zadaného zpoždění provedla funkci zpětného volání.
Podobně, když provádíte síťové operace asynchronně, libuv tyto operace zpracovává bez blokování způsobem, který zajistí, že ostatní úlohy mohou pokračovat ve zpracování bez čekání na vstup/výstup (I/O). konec.
Fronta zpětného volání a událostí
Fronta zpětného volání a událostí je místo, kde funkce zpětného volání čekají na provedení. Po dokončení asynchronní operace z libuv se do této fronty přidá její odpovídající funkce zpětného volání.
Posloupnost probíhá takto:
- JavaScript přesouvá asynchronní úlohy do libuv, aby je zpracoval, a okamžitě pokračuje ve zpracování další úlohy.
- Když asynchronní úloha skončí, JavaScript přidá svou funkci zpětného volání do fronty zpětného volání.
- JavaScript stále provádí další úlohy v zásobníku volání, dokud není vše hotovo v aktuálním pořadí.
- Jakmile je zásobník volání prázdný, JavaScript se podívá na frontu zpětných volání.
- Pokud je ve frontě zpětné volání, vloží první do zásobníku volání a provede jej.
Tímto způsobem asynchronní úlohy neblokují hlavní vlákno a fronta zpětných volání zajišťuje, aby se jejich odpovídající zpětná volání prováděla v pořadí, v jakém byla dokončena.
Cyklus smyčky událostí
Smyčka událostí má také něco, čemu se říká fronta mikroúloh. Tato speciální fronta ve smyčce událostí obsahuje mikroúlohy naplánované na provedení, jakmile se dokončí aktuální úloha v zásobníku volání. K tomuto spuštění dojde před další iterací vykreslování nebo smyčky událostí. Mikroúlohy jsou úkoly s vysokou prioritou, které mají přednost před běžnými úkoly ve smyčce událostí.
Při práci s Promises se běžně vytváří mikroúloha. Kdykoli je příslib vyřešen nebo odmítnut, odpovídá tomu .pak() nebo .chytit() zpětná volání se připojí k frontě mikroúloh. Tuto frontu můžete použít ke správě úloh, které vyžadují okamžité provedení po aktuální operaci, jako je aktualizace uživatelského rozhraní vaší aplikace nebo zpracování změn stavu.
Například webová aplikace, která provádí načítání dat a aktualizuje uživatelské rozhraní na základě získaných dat. Uživatelé mohou toto načítání dat spustit opakovaným kliknutím na tlačítko. Každé kliknutí na tlačítko zahájí operaci asynchronního načítání dat.
Bez mikroúloh by smyčka událostí pro tuto úlohu fungovala následovně:
- Uživatel na tlačítko opakovaně kliká.
- Každé kliknutí na tlačítko spustí operaci asynchronního načtení dat.
- Jakmile jsou operace načítání dat dokončeny, JavaScript přidá jejich odpovídající zpětná volání do běžné fronty úloh.
- Smyčka událostí zahájí zpracování úloh v běžné frontě úloh.
- Aktualizace uživatelského rozhraní na základě výsledků načítání dat se spustí, jakmile to běžné úlohy dovolí.
U mikroúloh však smyčka událostí funguje jinak:
- Uživatel opakovaně klikne na tlačítko a spustí operaci asynchronního načtení dat.
- Jakmile jsou operace načítání dat dokončeny, smyčka událostí přidá jejich odpovídající zpětná volání do fronty mikroúloh.
- Smyčka událostí zahájí zpracování úloh ve frontě mikroúloh ihned po dokončení aktuální úlohy (kliknutí na tlačítko).
- Aktualizace uživatelského rozhraní založená na výsledcích načítání dat se provádí před další pravidelnou úlohou, což poskytuje citlivější uživatelskou zkušenost.
Zde je příklad kódu:
const fetchData = () => {
returnnewPromise(resolve => {
setTimeout(() => resolve('Data from fetch'), 2000);
});
};
document.getElementById('fetch-button').addEventListener('click', () => {
fetchData().then(data => {
// This UI update will run before the next rendering cycle
updateUI(data);
});
});
V tomto příkladu volá každé kliknutí na tlačítko „Načíst“. fetchData(). Každá operace načítání dat je naplánována jako mikroúloha. Na základě načtených dat se aktualizace uživatelského rozhraní provede okamžitě po dokončení každé operace načtení, před jakýmikoli jinými úlohami vykreslování nebo smyčky událostí.
To zajišťuje, že uživatelé uvidí aktualizovaná data, aniž by došlo ke zpoždění kvůli jiným úkolům ve smyčce událostí.
Použití mikroúkolů ve scénářích, jako je tento, může zabránit trhání uživatelského rozhraní a zajistit rychlejší a plynulejší interakce ve vaší aplikaci.
Důsledky smyčky událostí pro vývoj webu
Pochopení smyčky událostí a způsobu použití jejích funkcí je zásadní pro vytváření výkonných a citlivých aplikací. Smyčka událostí poskytuje asynchronní a paralelní možnosti, takže můžete efektivně zpracovávat složité úlohy ve vaší aplikaci, aniž byste ohrozili uživatelskou zkušenost.
Node.js poskytuje vše, co potřebujete, včetně webových pracovníků k dosažení dalšího paralelismu mimo hlavní vlákno JavaScriptu.