Rendering: redarea, recalcularea unui copac / aspect, styling
Notă: traducerea notei Rendering: repaint, reflow / relayout, restyle de la Stoyan Stefanov. Acesta acoperă o mulțime de aspecte aplicate de redare a paginilor în browsere și de construire a unui flux de documente. Notele sunt în continuare italice. Termenul reflow este apoi tradus drept "recalcularea arborelui de randare", pentru ao separa de termenul "repaint" (redactarea paginii reale).
Procesul de desen
Diferitele browsere fac acest lucru în moduri diferite, dar următoarea diagramă oferă o înțelegere a procesului în ansamblu și este mai mult sau mai puțin potrivită pentru toate browserele de îndată ce se încarcă tot codul paginii.
Pentru copaci nu puteți vedea pădurea
Să luăm în considerare următorul exemplu.
Sursa HTML:
DOM copac. care corespunde cu documentul HTML conține în principal, un nod pentru fiecare etichetă și un nod pentru fiecare bucată de text între etichetele (pentru simplitate, putem ignora faptul că decalajele sunt, de asemenea, noduri de text):
Acest arbore de redare este partea vizibilă a arborelui DOM. Lipsesc o serie de lucruri - de exemplu, titlul paginii și elementele ascunse - dar există noduri suplimentare (sau cadre sau blocuri) pentru afișarea șirurilor de text.
Elementul rădăcină al arborelui de randare este un cadru (bloc) care conține toate celelalte elemente. Vă puteți gândi la aceasta ca o parte internă a ferestrei browserului, deoarece limitează zona în care poate fi localizată pagina. Din punct de vedere tehnic, în WebKit nodul rădăcină se numește RenderView. și corespunde containerului original cu specificația CSS și are un domeniu dreptunghiular care se extinde de la începutul paginii (0. 0) la (window.innerWidth.window.innerHeight).
Redactarea și recalcularea arborelui de redare
Pe pagină există întotdeauna cel puțin un calcul al fluxului de documente împreună cu randarea acestuia (cu excepția cazului în care, desigur, nu sunteți un fan al unei pagini goale în browser :)). După aceea, schimbarea informațiilor de intrare care au fost folosite pentru a face pagina poate avea ca rezultat un (sau ambele) elemente de mai jos.
- Va trebui să recalculați unele părți ale copacului de redresare (sau chiar întreg arborele). Acest proces se numește recalcularea arborelui de randare (reflow) sau re-layout-ul documentului (re-layout). Rețineți că există întotdeauna o astfel de recalculare: când prima pagină este afișată.
- Unele părți ale ecranului trebuie să fie actualizate, fie pentru că proprietățile geometrice ale nodurilor s-au schimbat, fie unele dintre stilurile lor (de exemplu, culoarea de fundal). Acest proces se numește repaint, redraw.
Redrawarea și recalculările pot fi un exercițiu foarte costisitor, care afectează negativ experiența utilizatorului și încetinesc răspunsul general al interfeței la acțiunile utilizatorului.
Ce cauzează recalcularea sau redesenarea
Orice lucru care modifică cumva informațiile folosite pentru a construi arborele de randare (care conduce în mod natural la necesitatea de a recrea copacul) poate duce la o recalculare sau redirecționare. De exemplu:
- Adăugați, eliminați sau actualizați nodurile DOM.
- Ascunderea unui nod DOM cu afișare: nici una (redistribuire sau redrafiere) sau vizibilitate: ascunsă (numai redraționarea, geometria nu se modifică).
- Mișcare, animație a elementului DOM pe pagină.
- Adăugarea unui fișier de stil, schimbarea proprietăților de stil ale elementelor.
- Acțiuni personalizate, cum ar fi redimensionarea unei ferestre, modificarea mărimii fontului sau (doar că nu) derularea paginii.
Să aruncăm o privire la câteva exemple:
Unele recalculații ale arborelui de randare pot fi mai grele. Merită să luați în considerare aceste operațiuni în ceea ce privește arborele de redare: dacă modificările se referă numai la nodul care este un descendent direct al corpului, este posibil ca alte noduri să nu fie afectate. Dar ce se întâmplă dacă începeți să animați și să creșteți blocul din partea de sus a paginii, care va muta restul paginii în jos? Se pare că va fi foarte costisitor.
Navigatorii mai inteligenți
Deoarece numărarea fluxurilor de documente și redraje asociate cu schimbarea arborelui de redare sunt operații foarte complexe, browserele încearcă să neutralizeze toate efectele negative. O abordare este refuzul de a produce o parte din lucrare. Cel puțin nu în acest moment. Browserul poate crea o anumită coadă în care vor fi făcute modificările făcute de scripturi și vor efectua aceste modificări în loturi. În acest caz, mai multe modificări, fiecare dintre acestea implicând recalcularea, pot fi combinate într-una și se va face doar o singură recalculare. Browserele pot, de asemenea, să reseta starea coadă (trage) pagina după un anumit timp (100-200ms) sau să ajungă la o anumită sumă (10-20) din aceste modificări.
Dar, uneori, scripturile pot preveni comportamentul optimizat al browserelor și pot determina să se aplice toate modificările de așteptare chiar în această secundă. Acest lucru se întâmplă atunci când solicitați următoarele informații despre stiluri:
- offsetTop. offsetLeft. offsetWidth. offsetHeight,
- scrollTop / Stânga / Lățime / Înălțime,
- ClientTop / Stânga / Lățime / Înălțime,
- getComputedStyle () sau currentStyle în IE.
Toate opțiunile de mai sus solicită informații despre stilul site-ului DOM din browser. Această solicitare determină browserul să efectueze toate operațiile în așteptare pentru a furniza informații actualizate. Toate acestea conduc la punerea în aplicare a recalculației (și aparent redesenarea).
De exemplu, o idee proastă ar fi să setați stiluri, cerând informații despre ele în același loc (de exemplu, în interiorul unei buclă):
Reducerea recalculațiilor și retragerilor
Pentru a reduce efectele negative ale recalculare / retrasarea (relativ experiență de utilizare) reprezintă, mai presus de toate, pentru a minimiza orice referire la informațiile de stil la browser-ul poate optimiza conversia desenului copac. Ce este necesar pentru asta?
- Nu modificați proprietățile individuale ale stilului unul câte unul. Pentru a scala codul și a crește viteza de răspuns a interfeței, trebuie să modificați numele claselor, nu stilurile. Dar aceasta presupune clase statice. Dacă stilurile sunt complet dinamice (de exemplu elementele "ascendente"), atunci trebuie să editați proprietatea cssText în loc să efectuați modificări ale proprietății de stil a elementului însuși.
- Colectați modificările copacului DOM "offline" și folosiți-le într-o companie. "Offline" în acest caz înseamnă că modificările nu apar pe un arbore DOM live. De exemplu:
- utilizați documentFragment pentru rezultate intermediare,
- clonați-vă nodurile, schimbați copii și apoi le înlocuiți cu originale,
- ascundeți elementul cu afișaj: nici unul (1 recalculare + redraw), apoi aplicați toate modificările, apoi restaurați afișarea (o altă redistribuire + redirecționare). În acest fel, puteți salva sute de potențiale recalculații ale arborelui de redare.
- Nu cereți stiluri reale prea des. Dacă lucrați cu valorile calculate, solicitați-o o dată, memorați-o într-o variabilă locală și lucrați cu o copie locală. După cum se aplică la exemplul negativ de mai sus:
- De fiecare dată înainte de a efectua modificări, calculați ce efect vor avea asupra arborelui de randare (puteți estima numărul de noduri DOM). De exemplu, utilizarea poziționării absolute convertește un element într-un copil al corpului tuturor arborilor din desen, deci nu va afecta cât mai multe noduri ca și animația. Unele elemente (situate mai adânc în arborele de randare) pot fi în sfera acestui element, însă ele vor necesita doar redraționarea și nu alocarea arborelui.
instrumente
Aproximativ un an în urmă, nu era nimic care să furnizeze informații cu privire la recalcularea și redesenarea pagina în browser (acest lucru nu poate fi cazul, bănuiesc că SM au avut propriile lor instrumente interne pentru dezvoltatori, dar nimeni nu știa despre ei, pentru că au fost îngropate în profunzimea MSDN: P). Acum situația sa schimbat și foarte mult.
Mai întâi, evenimentul MozAfterPaint a apărut în construcțiile nocturne ale lui Firefox, astfel încât plugin-urile au devenit posibile, cum ar fi acesta (de la Kyle Scholz), care folosește acest eveniment. mozAfterPaint - este foarte cool, dar raportează doar momentul revopsării (și nu recalcularea arborelui de redare, care este mai scump).
Mai departe. DynaTrace Ajax și mai târziu Speedtracer de la Google (notă: ambele Tracy (urme) :)) sunt instrumente excelente pentru urmărirea și alocările redesenează, primul pentru IE concepute, al doilea - pentru WebKit.
Într-o zi anul trecut, Douglas Crockford a menționat că putem face lucruri stupide în CSS, dar nu știm despre ele. Și acum există ceva de obiectat față de asta. Sunt puțin implicat în proiect în acest stadiu, am abordat următoarea problemă: o ușoară creștere a fontului utilizatorului (în IE6) descărcat CPU până la 100%, timp de 10-15 minute înainte de a apare pagina din nou pe ecran.
Excelent, avem instrumente, deci pentru noi nu mai putem fi indulgenți în ceea ce privește comportamentul idiotic în CSS.
Ei bine, cu excepția, poate, un lucru: ar fi bine dacă ar exista o unealtă care ar arăta arborele de randare în plus față de arborele DOM?
Exemple practice
Să aruncăm o privire mai atentă la instrumentele specificate și să demonstrăm cu ajutorul lor diferența dintre schimbarea stilurilor (restyle, modificările în arborele de desen nu se referă la geometrie), recalcularea (reflow), care modifică aspectul documentului și refacerea.
Să comparăm cele două căi de a face același lucru. Mai întâi vom schimba unele stiluri (care nu afectează aspectul) și după fiecare schimbare vom cere o proprietate de stil, fără nici o schimbare asociată cu schimbarea.
Și apoi la fel, numai după toate schimbările în stiluri vor fi efectuate toate solicitările de informații:
În ambele cazuri, iată definițiile variabilelor utilizate:
Acum permiteți executarea acestor două exemple de modificări de stil făcând clic pe document. Pagina de testare se află aici: restyle.html (faceți clic pe "dude"). Să numim testul restyle.
În cel de-al doilea test, vor fi aproape la fel, doar vom schimba și informațiile despre aspect:
Acest caz să sunăm la testul de relayout, sursa este aici.
Asta produce DynaTrace pentru primul test (stiluri).
Inițial, pagina noastră a fost încărcată, apoi dau o singură dată clic pentru a executa primul script (solicitând stiluri de fiecare dată, aproximativ 2 secunde). Apoi, dau din nou clic pentru a executa al doilea scenariu (interogări la stiluri după toate modificările, aproximativ 4 secunde)
Acest instrument arată în ce moment pagina a terminat încărcarea (acesta este logo-ul IE). Apoi, cursorul mouse-ului este localizat în zona responsabilă pentru procesarea clicului. Zoom in (cool!), Și aici este o imagine mai detaliată:
Din nou, mărim scara și vedem că pe lângă banda "rendering" avem și alta - "recalcularea arborelui de randare", pentru că în acest test îl creăm în mod conștient în plus față de redraw.
Acum, să testați aceeași pagină în Chrome și să examinăm rezultatele SpeedTracer.
Acesta este primul test pentru schimbarea stilurilor cu o scară mărită și o revizuire a ceea ce se întâmplă.
Dacă este scurtă, atunci după clic apare un desen. Dar în cazul primului clic, 50% din timp este cheltuit pentru recalcularea stilurilor. De ce? Deoarece solicităm informații despre stiluri (care nu sunt asociate chiar cu stilurile) după fiecare schimbare.
Mărim evenimentele și vedem în detaliu ce se întâmplă cu adevărat: după primul clic, stilurile sunt recalculate de 3 ori. După a doua, o singură dată.
Să facem acum testul pentru a schimba aspectul. Imaginea de ansamblu arată la fel ca și ultima oară:
O ușoară diferență între aceste instrumente este că SpeedTracer nu arată momentul în care sarcina de modificare a aspectului este planificată și adăugată la coadă, iar DynaTrace arată. Astfel, DynaTrace nu afișează diferența dintre schimbarea stilurilor și modificarea aspectului, cum ar fi SpeedTracer. Poate, doar IE nu face diferența între ei? De asemenea, DynaTrace nu a arătat trei alocări ale arborelui de randare în primul caz al celui de-al doilea test (atunci când solicităm informații despre stiluri după fiecare modificare a aspectului). Poate că așa funcționează IE?
Mai jos sunt date suplimentare despre aceste două teste după ce le executați de câteva ori.
- În Chrome, refuzul de a interoga stilurile calculate atunci când le schimbați este de aproximativ 2,5 ori mai rapid (modificați testul pentru stiluri) și de 4,42 ori mai rapid dacă schimbați atât stilurile, cât și aspectul (modificați aspectul testului).
- În Firefox - în 1,87 și 1,64 ori mai rapid, respectiv.
Pentru toate browserele, schimbarea stilurilor este de aproximativ două ori mai rapidă decât schimbarea stilurilor și a aspectului paginii. Cu excepția IE6, unde diferența este de 4 ori.
concluzie
Mulțumesc că ați citit acest loc. Încercați să jucați cu instrumentele menționate mai sus și examinați viteza de redare a paginilor. Permiteți-mi să reamintesc încă o dată acei termeni folosiți în articol.
- Arborele de redare este partea vizuală a arborelui DOM.
- Nodurile din arborele desen sunt numite cadre sau blocuri.
- Schimbarea arborelui de redare se numește recalcularea și aspectul Mozilla în toate celelalte browsere, aparent.
- Actualizarea rezultatelor alocării arborelui de randare pe ecran se numește repaint, redraw (în IE / DynaTrace).
- SpeedTracer introduce conceptul de "recalculare a stilurilor" (stiluri care nu schimbă geometria) împotriva "aspectului".
Și câteva referiri la rămas bun. Este demn de remarcat faptul că primele trei dintre aceste materiale explică situația mai profund din punctul de vedere al browserului, și nu din punctul de vedere al dezvoltatorului (așa cum am încercat să fac).