Sunteți pe pagina 1din 15

Lecția 7.

Performanța codului
La această lecție vom studia cum poate fi măsurată performanța codului, și cum poate fi
scris un cod eficient și performant. Vom studia tot ce ține de evenimentele ciclice JavaScript
și cum acestea afectează codul scris.
Folosirea unui ciclu pentru a adăuga conținut
În ultima lecție, am folosit o buclă for pentru a crea două sute de paragrafe, pentru a le
adăuga ascultători de evenimente și pentru a le adăuga la pagină. Să aruncăm o altă privire
asupra buclei for, dar de data aceasta fără codul ascultătorului de evenimente:
for (let i = 1; i <= 200; i++) {
const newElement = document.createElement('p');
newElement.textContent = 'This is paragraph number ' + i;

document.body.appendChild(newElement);
}

Să recapitulăm rapid codul pentru a vedea unde putem aduce îmbunătățiri.


Acest cod:
- creează un element de paragraf
- adaugă un text la paragraf
- adaugă paragraful la pagină
... și face asta de două sute de ori.
Din moment ce dorim să se facă două sute de lucruri, cel mai bun mod de a face acest lucru
este cu o buclă for, astfel încât codul să fie inevitabil. Cu toate acestea, codul din buclă for
nu este atât de eficient și există destul de multe lucruri pe care le-am putea face pentru a
îmbunătăți acest cod. Am putea:
- creați un element container părinte în afara buclei
- am putea adăuga toate elementele de paragraf noi la acest container părinte
- adăugăm acest container părinte elementului body> în loc să îl adăugăm de fiecare
dată prin buclă.
Să vedem toate aceste modificări:
const myCustomDiv = document.createElement('div');

for (let i = 1; i <= 200; i++) {


const newElement = document.createElement('p');
newElement.innerText = 'This is paragraph number ' + i;

myCustomDiv.appendChild(newElement);
}
document.body.appendChild(myCustomDiv);

Apoi putem testa timpul necesar pentru a rula efectiv acest cod!
Testarea performanței codului
Modul standard de a măsura cât durează codul pentru a rula este folosind
performance.now(). performance.now() returnează un timestamp care este măsurat în
milisecunde, deci este extrem de precis. Cât de precisă? Iată ce spune pagina documentației
sale:
precis la cinci miimi de milisecundă (5 microsecunde)
Este incredibil de precis!
Dacă ați folosit vreodată o procedură de sincronizare într-un alt limbaj de programare,
atunci ați fi auzit de timpul Epoch (numit și timpul Unix sau timpul POSIX). Aceste
instrumente vă indică timpul care a trecut de la 1 ianuarie 1970 (primul ianuarie). Metoda
browserului performance.now()este ușor diferită prin aceea că începe să măsoare de la
momentul încărcării paginii. Informații detaliate pot fi găsite pe pagina documentației sale:
performance.now () pe MDN.
Iată pașii care trebuie utilizați pentru ca performance.now() să măsoare viteza codului dvs.:
- utilizați performance.now() pentru a obține ora inițială de început pentru cod
- rulați codul pe care doriți să-l testați
- executați performance.now() pentru a obține o altă măsurare a timpului
- scade timpul inițial din timpul final
Adăugarea a două sute de paragrafe la pagină va fi de fapt relativ rapidă, așa că hai să
încetinim lucrurile folosind un set de bucle for imbricate care contează doar de la una la o
sută ... de o sută de ori!
for (let i = 1; i <= 100; i++) {
for (let j = 1; j <= 100; j++) {
console.log('i and j are ', i, j);
}
}

Apoi, vom adăuga codul performance.now() pentru a măsura cât durează aceste bucle:
const startingTime = performance.now();

for (let i = 1; i <= 100; i++) {


for (let j = 1; j <= 100; j++) {
console.log('i and j are ', i, j);
}
}

const endingTime = performance.now();


console.log('This code took ' + (endingTime - startingTime) +
' milliseconds.');

Folosim performance.now() pentru a calcula timpul total pentru executarea codului.


Să revenim la codul nostru original de adăugare a două sute de paragrafe la pagină pentru a
vedea cât durează acel cod. Introduceți în consolă primul cod în care am utilizat ciclul for și
ultimul și calculați-le performanța pentru a vedea cât durează.
Folosirea unui fragment de document
Până în prezent, am adus o serie de îmbunătățiri la cod. Cu toate acestea, există încă un
lucru care pare să nu fie atât de grozav; trebuie să creeze un element străin <div> doar
pentru a menține toate etichetele <p> astfel încât să le putem adăuga și apoi vom adăuga
acest lucru <div> la elementul <body>. Deci, în final, avem un extra <div>care nu este cu
adevărat necesar. Era necesar, pentru că am vrut să adăugăm fiecare nou <p>în loc de
<body>.
De ce facem asta? Browserul lucrează constant pentru ca ecranul să se potrivească cu DOM.
Când adăugăm un element nou, browserul trebuie să ruleze printr-un calcul reflow (pentru
a determina noul aspect al ecranului) și apoi repaint pe ecran. Acest lucru necesită timp.
Dacă am fi adăugat fiecare nou paragraf la elementul corp, atunci codul ar fi fost mult mai
lent, deoarece acest lucru ar determina browserul să treacă prin procesul de reflow și
repictare pentru fiecare paragraf . Chiar ne dorim ca browserul să facă acest lucru o singură
dată, așa că trebuie să atașăm fiecare paragraf nou la ceva, dar nu vrem să avem un element
suplimentar, care nu este necesar, pentru a fi adăugat la DOM.
Tocmai de aceea avem DocumentFragment! Conform documentației, un
DocumentFragment:
reprezintă un obiect de document minim care nu are părinte. Este folosit ca o versiune
ușoară a documentului care stochează un segment al unei structuri de documente compuse
din noduri la fel ca un document standard.
Deci, este ca și cum ai crea un alt arbore DOM ușor. Dar partea benefică a acestui lucru este
ceea ce scrie în continuare:
Diferența esențială este că, deoarece fragmentul documentului nu face parte din structura
activă a arborelui documentului, modificările aduse fragmentului nu afectează documentul,
nu provoacă reflux sau nu implică niciun impact asupra performanței care poate apărea
atunci când se fac modificări.
Cu alte cuvinte, modificările aduse unui DocumentFragment se întâmplă în afara ecranului;
în timp ce construiți acest lucru nu există costuri de reflux și repaint. Deci, exact de asta
avem nevoie!
Putem folosi metoda .createDocumentFragment()pentru a crea un obiect
DocumentFragment gol. Acest cod ar trebui să vă fie foarte familiar, deoarece arată foarte
similar cu document.createElement().
const myDocFrag = document.createDocumentFragment();

Să rescriem codul nostru pentru a utiliza un DocumentFragment în loc de <div>.


const fragment = document.createDocumentFragment(); // ←
uses a DocumentFragment instead of a <div>

for (let i = 0; i < 200; i++) {


const newElement = document.createElement('p');
newElement.innerText = 'This is paragraph number ' + i;

fragment.appendChild(newElement);
}

document.body.appendChild(fragment); // reflow and repaint


here -- once!
Recapitulare
În această secțiune, am făcut o scurtă scufundare în implicațiile de performanță ale codului
pe care îl scriem. Ne-am uitat la o anumită bucată de cod și am venit cu modalități prin care
am putea îmbunătăți performanțele sale pur și simplu prin rearanjarea când rulează codul
(mutarea codului de inițializare din buclă for).
De asemenea, am analizat cum să măsurăm cât durează codul pentru a rula folosind
performance.now().
În cele din urmă, ne-am uitat la utilizarea unui DocumentFragment pentru a preveni
probleme de performanță și pentru a preveni adăugarea de elemente inutile în DOM.

Cercetări suplimentare

 performance.now () pe MDN
 Interfață de performanță pe MDN
 DocumentFragment Interface pe MDN
 documente createDocumentFragment pe MDN
Reflow & Repaint
Am menționat Reflow și Repaint în ultima secțiune, acum este timpul să aruncăm o privire
mai atentă.
Reflow este procesul prin care browserul dispune pagina. Se întâmplă atunci când afișați
DOM-ul pentru prima dată (în general după ce DOM și CSS au fost încărcate) și se întâmplă
din nou de fiecare dată când ceva ar putea schimba aspectul. Acesta este un proces destul
de scump (lent).
Repaint are loc după reflow pe măsură ce browserul atrage noul aspect pe ecran. Acest
lucru este destul de rapid, dar totuși doriți să limitați cât de des se întâmplă.
De exemplu, dacă adăugați o clasă CSS la un element, browserul recalculează deseori
aspectul întregii pagini - acesta este un reflow și unul repaint!
Să luăm un exemplu realist. Spuneți că scrieți următoarea mare platformă de blog și doriți să
aveți un buton „eliminare spam” pentru administrator. HTML-ul dvs. arată astfel:
<div id="comments">
<div class="comment"> <!-- some content --> </div>
<div class="comment"> <!-- some content --> </div>
<div class="comment"> <!-- some content --> </div>
</div>

Când rulăm filtrul de spam, descoperim că comentariile unu și doi trebuie eliminate.
Dacă apelăm pur și simplu .removeChild() la fiecare dintre cele două comentarii care trebuie
eliminate, este vorba de o refluxare și o repaint pentru fiecare modificare (deci un total de 2
refluxuri și 2 repaint). Am putea reconstrui întregul lucru într-un DocumentFragment și să
înlocuim #comments- l - acesta este momentul pentru a reconstrui (posibil implicând citirea
fișierelor sau a datelor), plus cel puțin o reflow și un repaint.
Sau am putea să ascundem #comments , să ștergem spamul și să-l afișăm din nou - asta este
surprinzător de rapid, la costul unei refluxuri și a două repaint (și puțin altceva). Este rapid,
deoarece ascunderea nu schimbă aspectul, ci doar șterge acea secțiune a ecranului (1
repiaint). Când faceți secțiunea modificată vizibilă din nou, aceasta este o refluxare și un
repaint.
// hide #comments
document.getElementById("comments").style.display = "none";

// delete spam comments

// show #comments
document.getElementById("comments").style.display = "block";

În general, dacă trebuie să faceți un grup de modificări, ascunderea / schimbarea tuturor /


afișarea este un model excelent de utilizat dacă modificările sunt relativ conținute.

DOM virtual
Apropo, acesta este motivul pentru care React și alte biblioteci „virtual DOM” sunt atât de
populare. Nu faceți modificări la DOM, ci faceți modificări la o altă structură (un „DOM
virtual”), iar biblioteca calculează cel mai bun mod de a actualiza ecranul pentru a se potrivi.
Practic este că trebuie să refaceți codul pentru a utiliza orice bibliotecă adoptați și, uneori,
puteți face o treabă mai bună actualizând singur ecranul (pentru că înțelegeți propria
situație unică).
Recapitulare
În această secțiune, am aruncat o scurtă privire la ceea ce este refluxul și revopsirea și am
văzut cum pot influența performanța unui site web.
Reflow este procesul de calcul al dimensiunilor și poziției elementelor paginii. Aceasta este o
sarcină calculatoare intensă (lentă). Repaint este procesul de atragere a pixelilor pe ecran.
Acest lucru este mai rapid decât reflow, dar încă nu este un proces rapid. Trebuie să vă
asigurați că codul dvs. cauzează cel mai mic număr de refluxuri posibil.

Cercetări suplimentare

 Curs de optimizare a performanței site-ului web de Udacity


 Minimizarea refluxului browserului din PageSpeed Tools Ghiduri
 Evitați aspectele mari și complexe și aruncările de aspect  din ghidurile
fundamentale ale Google pentru web
 Referință privind analiza performanței din Ghidurile fundamentale Google
pentru web
 Articolul Restituirile & Repictează: Performanța CSS Efectuarea JavaScript
- ul lent?

Filetare unică
Este posibil să fi auzit că JavaScript are un singur fir, dar ce înseamnă asta? Potrivit
Wikipedia, un singur fir este:
procesarea unei comenzi pe rând
Ok, deci JavaScript poate „procesa” o comandă la rând. Opusul single-threading este
multithreading. Există numeroase argumente pro și contra în care nu vom intra (nu ezitați să
consultați articolul Wikipedia despre filetare pentru mai multe informații despre argumente
pro și contra). Vom arunca o privire asupra modelului cu un singur fir JavaScript și cum / de
ce ar trebui să scriem codul nostru pentru a profita de acesta.
Să ne uităm la câteva coduri:
function addParagraph() {
const para = document.createElement('p');
para.textContent = 'JavaScript is single threaded!';
document.body.appendChild(para);
}

function appendNewMessage() {
const para = document.createElement('p');
para.textContent = "Isn't that cool?";
document.body.appendChild(para);
}

addParagraph();
appendNewMessage();

Ținând cont de natura unică a firului JavaScript (ceea ce înseamnă că poate îndeplini o
singură sarcină la un moment dat), să descompunem acest cod în ordinea în care va rula:
- funcția addParagraph() este declarată pe linia 1
- funcția appendNewMessage() este declarată pe linia 6
- addParagraph() este chemat pe linia 13
o execuția se mută în funcție și execută toate cele trei linii în ordine
o acum că funcția este terminată, execuția revine la locul unde a fost apelată
- funcția appendNewMessage()se utilizează pe linia 14
o execuția se mută în funcție și execută toate cele trei linii în ordine
o acum că funcția este terminată, execuția revine la locul unde a fost apelată
- programul se încheie deoarece toate liniile de cod au fost executate.
Sperăm că ordinea în care a fost executat acest cod nu a fost surprinzătoare. Există câteva
lucruri la care vreau în mod special să fii atent. În primul rând, este caracterul executării
până la finalizarea codului. Când addParagraph() este invocat pe linia 13, tot codul din
funcție este executat : nu doar execută unele linii și lasă alte linii pentru a fi executate mai
târziu. Se execută întregul bloc de cod. Un al doilea lucru pe care vreau să-l subliniez este că
addParagraph() este invocat, rulează și se termină înainte de a fi invocat
appendNewMessage() (inclusiv o posibilă refluxare și repaint); JavaScript nu execută mai
multe linii / funcții în același timp (aceasta este o singură conversație ... se procesează o
comandă pe rând!).
Ce se întâmplă dacă am schimba ușor acest cod pentru a crea funcții imbricate:
function addParagraph() {
const para = document.createElement('p');
para.textContent = 'JavaScript is single threaded!';

appendNewMessage();
document.body.appendChild(para);
}

function appendNewMessage() {
const para = document.createElement('p');

para.textContent = "Isn't that cool?";


document.body.appendChild(para);
}

addParagraph();

Observați că apelul către appendNewMessage() este situat în interiorul funcției


addParagraph(). În primul rând, addParagraph() este invocat. Apoi appendNewMessage()
este invocat pe linia 5. Odată ce appendNewMessage() a rulat, executarea revine și termină
rularea ultimei linii de cod din funcție addParagraph()... dar de unde știe cum să facă asta?
Cum știe motorul JavaScript de unde a rămas și cum să revină la el?
Stivă de apeluri
Motorul JavaScript păstrează o stivă de apeluri (practic o listă) a funcțiilor care rulează. Când
este invocată o funcție, aceasta este adăugată la listă. Când tot codul din interiorul unei
funcții a fost rulat, atunci funcția este eliminată din stiva de apeluri. Partea interesantă a
unei stive de apeluri este că o funcție nu trebuie să fie finalizată înainte ca o altă funcție să
fie adăugată la stiva de apeluri.
Să vedem cum funcționează acest lucru!
https://www.youtube.com/watch?v=J9iKeNhoXNM&feature=emb_logo
Recapitularea stivei de apeluri
În această secțiune, ne-am uitat la modul în care JavaScript este un limbaj de programare cu
un singur fir, ceea ce înseamnă că poate executa un singur lucru la un moment dat. Am
analizat modul în care JavaScript ține evidența funcțiilor care rulează utilizând Call Stack.
Cercetări suplimentare

 Apelați stiva pe MDN


 Apelați stiva pe Wikipedia

Sincronicitatea codului
În secțiunea anterioară din Call Stack, am folosit termenii:
- alergare până la finalizare
- cu un singur fir
Un alt termen pentru aceasta este sincron . Prin definiție, „sincron” înseamnă:
existente sau care apar în același timp
Tot codul pe care l-am analizat rulează în ordine, în același timp. Funcțiile sunt adăugate la
teancul de apeluri, apoi sunt eliminate din teancul de apeluri după ce au terminat. Cu toate
acestea, există un cod care nu este sincron - ceea ce înseamnă că codul este scris la fel ca
orice alt cod, dar este executat la un moment dat ulterior. Sună deloc familiar? Tocmai ați
lucrat cu ea:
const links = document.querySelectorAll('input');
const thirdField = links[2];

thirdField.addEventListener('keypress', function
handleKeyPresses(event) {
console.log('a key was pressed');
});

... ascultători de evenimente! Cea mai mare parte a acestui cod este sincronă așa cum
sunteți obișnuiți. Dar funcția ascultătorului de evenimente handleKeyPresses nu este
invocată imediat, este invocată la un moment dat ulterior.
Te-ai întrebat vreodată despre asta? Unde merge codul? Dar „stiva de apeluri” despre care
am aflat? Este ascuns undeva în teancul de apeluri?
Să ne uităm la acest fragment de cod:
console.log('howdy');
document.addEventListener('click', function numbers() {
console.log('123');
});
console.log('ice cream is tasty');

Codul va rula în această ordine:


- 'howdy' va fi conectat la consolă
- 'ice cream is tasty' va fi conectat la consolă
Șirul '123' va fi înregistrat numai dacă există un clic. Dacă nu se face clic pe pagină, este
posibil ca acest cod să nu ruleze niciodată! Dar unde este? Unde s-a dus funcția numbers
care deține codul console.log('123');?

Rularea codului mai târziu


Dar există aceleași întrebări pentru acest cod ca și pentru .addEventListener() cod:
- unde merge funcția să aștepte?
- cum funcționează funcția atunci când este nevoie?
Acest lucru se întâmplă din cauza buclei de eveniment JavaScript!
Bucla de eveniment JavaScript
Cea mai simplă explicație a modelului simultan JavaScript utilizează două reguli: Dacă un
anumit JavaScript rulează, lăsați-l să ruleze până când este terminat („run-to-complete”).
Dacă nu rulează JavaScript, rulați orice handler de evenimente în așteptare.
Deoarece cea mai mare parte a JavaScript-ului este rulat ca răspuns la un eveniment, acesta
este cunoscut sub numele de buclă de eveniment : Ridicați următorul eveniment, rulați
handler-ul și repetați.

Există trei părți la care trebuie să vă gândiți în jurul buclei evenimentului:


- pila de apeluri
- API-uri web / browserul
- o coadă de evenimente
Nu tot codul pe care îl scriem este cod JavaScript 100% . O parte din cod interacționează cu
API-urile web (cunoscute și sub numele de „API-uri de browser”). Există multe alte exemple,
dar ambele .addEventListener()și setTimeout()sunt API-uri web.
Să ne uităm la acest cod:
console.log('howdy'); // 1
document.addEventListener('click', // 2
function numbers() {
console.log('123');
});
console.log('ice cream is tasty'); // 3

Mai întâi, browserul rulează acest bloc de cod până la finalizare - adică pașii 1, 2 și 3. Pasul 2
transmite un gestionar de evenimente ( numbers) către browser pentru o utilizare
ulterioară: browserul va deține această funcție până când apare un eveniment de clic .
Ce se întâmplă dacă cineva face clic înainte ca acest bloc de cod să fie terminat? Când există
un eveniment de clic și există deja un cod care rulează, funcția numbers nu poate fi
adăugată direct la Stack-ul de apeluri din cauza naturii executării până la finalizarea
JavaScript-ului; nu putem întrerupe niciun cod care s-ar putea întâmpla în prezent. Deci
funcția este plasată în Coadă. Când toate funcțiile din Stack-ul de apeluri s-au terminat
(cunoscut și sub denumirea de timp inactiv ), atunci Coada este verificată pentru a vedea
dacă așteaptă ceva. Dacă ceva este în coadă, atunci se execută, creând o intrare în teancul
de apeluri.

IMPORTANT: Principalele lucruri de reținut aici sunt


1) codul sincron actual rulează până la finalizare și
2) evenimentele sunt procesate atunci când browserul nu este ocupat.
Codul asincron (cum ar fi încărcarea unei imagini) rulează în afara acestei bucle și trimite un
eveniment când acesta este terminat.
Vezi și: https://www.youtube.com/watch?v=uBdemYBG-ek&feature=emb_logo.
Recapitulare
Această secțiune a descoperit modul în care funcționează JavaScript sub capotă; Am analizat
modul în care JavaScript, DOM și API-urile Web se potrivesc toate.
Mai exact, ne-am uitat la modul în care JavaScript este un limbaj de programare cu un singur
fir, ceea ce înseamnă că poate executa un singur lucru la un moment dat. Am analizat modul
în care JavaScript ține evidența funcțiilor care rulează utilizând Call Stack. De asemenea, ne-
am uitat la modul în care este tratat codul asincron.
Codul asincron face uz de JavaScript Event Loop. Orice cod asincron (cum ar fi setTimeout
sau funcția transmisă .addEventListener()) este gestionat de browser. Când acest cod
asincron este gata de executare, este mutat în coada unde așteaptă până când Stack-ul de
apeluri este gol. Ori de câte ori pila de apeluri este goală, codul se mută din coadă în pila de
apeluri și se execută.

Știind cum funcționează JavaScript și Event Loop ne poate ajuta să scriem un cod mai
eficient.
Cercetări suplimentare

 Model de concurență și Event Loop


 Prezentare generală a evenimentelor și gestionarilor
 Ce naiba este bucla evenimentului oricum?  de Philip Roberts pe YouTube

Rularea codului mai târziu


În mod similar cu codul .addEventListener()care se execută într-un moment mai târziu,
există funcția setTimeout()care va rula codul într-un punct mai târziu. Funcția setTimeout()
ia:
- o funcție pentru a rula ulterior
- numărul de milisecunde codul ar trebui să aștepte înainte de a rula funcția
Să vedem un exemplu:
setTimeout(function sayHi() {
console.log('Howdy');
}, 1000);

Dacă am rula acest cod, șirul 'Howdy'ar apărea în consolă în aproximativ 1.000 de
milisecunde sau în aproximativ o secundă.

Întrucât setTimeout() este un API furnizat de browser, apelul către setTimeout() conferă
funcția sayHi() browserului pe care pornește un cronometru. După terminarea
temporizatorului, funcția sayHi() se mută în Coadă. Dacă pila de apeluri este goală, atunci
funcția sayHi() este mutată în pila de apeluri și executată.
setTimeout() cu întârziere de 0
Un aspect interesant al setTimeout() este că putem trece o întârziere de 0 milisecunde.
setTimeout(function sayHi() {
console.log('Howdy');
}, 0); // ← 0 milliseconds!

S-ar putea să credeți că, deoarece are o întârziere de 0 milisecunde, funcția sayHi ar rula
imediat. Cu toate acestea, încă trece prin bucla de eveniment JavaScript. Deci, funcția este
predată browserului, unde browserul pornește un cronometru de 0 milisecunde. Deoarece
temporizatorul se termină imediat, funcția sayHi se va muta la Coadă și apoi la Stack-ul de
apeluri, după ce Stack-ul de apeluri a terminat executarea oricăror sarcini care rulează în
prezent.
Deci, de ce este de ajutor? Ei bine, această tehnică ne poate ajuta să convertim codul
potențial de lungă durată într-unul divizat pentru a permite browserului să gestioneze
interacțiunile utilizatorilor!

Descompuneți codul de lungă durată


Vă amintiți la o secțiune anterioară când am scris cod JavaScript pentru a adăuga două sute
de paragrafe la pagină? Acum, în loc să adăugăm două sute de paragrafe la pagină, dacă am
adăuga douăzeci de mii? Aceasta este o mulțime de elemente de creat, adăugat și inserat în
pagină!
Acum rețineți modul în care refluxul și repaint afectează performanța unei aplicații. Vrem să
scriem codul nostru JavaScript pentru a lua în considerare refluxul și repaint și pentru a
provoca cel mai mic număr dintre acestea.
Cu toate acestea, dorim să ne asigurăm și că aplicația noastră răspunde la interacțiunea
utilizatorului. În timp ce JavaScript rulează, pagina este „ocupată” și utilizatorul nu va putea
interacționa cu pagina (de exemplu, făcând clic pe un buton, completând un formular).
Rețineți că acest lucru se datorează faptului că JavaScript rulează sincron . Deci, va rula până
la finalizare (crearea, adăugarea și inserarea tuturor celor douăzeci de mii de elemente) și
face acest lucru înainte de a putea răspunde la orice acțiuni întreprinse de utilizator. Funcția
care creează toate aceste elemente și le adaugă la pagină va fi în Stack-ul de apeluri până
când va fi complet terminată.
O modalitate de a oferi utilizatorului șansa de a interacționa cu pagina este de a împărți
adăugarea conținutului în bucăți. Să facem acest lucru cu setTimeout():
let count = 1

function generateParagraphs() {
const fragment = document.createDocumentFragment();

for (let i = 1; i <= 500; i++) {


const newElement = document.createElement('p');
newElement.textContent = 'This is paragraph number '
+ count;
count = count + 1;

fragment.appendChild(newElement);
}

document.body.appendChild(fragment);

if (count < 20000) {


setTimeout(generateParagraphs, 0);
}
}

generateParagraphs();

Acest cod începe prin setarea unei variabile count la 1. Aceasta va urmări numărul de
paragrafe care au fost adăugate. Funcția generateParagraphs() va adăuga 500 de paragrafe
la pagina de fiecare dată când este invocat. Interesant este că există un apel setTimeout() la
sfârșitul funcției generateParagraphs(). Dacă există mai puțin de douăzeci de mii de
elemente, atunci setTimeout() va fi folosit pentru a apela funcția generateParagraphs().
Dacă încercați să rulați acest cod pe o pagină, puteți interacționa în continuare cu pagina în
timp ce rulează codul. Și nu se blochează din cauza apelurilor setTimeout().
Recapitulare setTimeout()
Funcția furnizată de browser setTimeout() preia o altă funcție și o întârziere și invocă funcția
după ce întârzierea a trecut.
Știind cum funcționează JavaScript Event Loop, putem folosi setTimeout() metoda pentru a
ne ajuta să scriem cod care permite browserului să gestioneze interacțiunile utilizatorilor.

Cercetări suplimentare

 documente setTimeout pe MDN


 Model de concurență și Event Loop
 Ce naiba este bucla evenimentului oricum?  de Philip Roberts pe YouTube
 Programare: setTimeout și setInterval

Dacă doriți să aflați mai multe despre cum să îmbunătățiți performanța site-urilor dvs.,
consultați cursul nostru Optimizarea randării browserelor realizat în parteneriat cu
Google.

S-ar putea să vă placă și