Performanță front-end 2021: optimizări de livrare
Publicat: 2022-03-10Acest ghid a fost susținut cu amabilitate de prietenii noștri de la LogRocket, un serviciu care combină monitorizarea performanței frontend , redarea sesiunii și analiza produselor pentru a vă ajuta să construiți experiențe mai bune pentru clienți. LogRocket urmărește valorile cheie, inclusiv. DOM finalizat, timpul până la primul octet, prima întârziere de intrare, CPU client și utilizarea memoriei. Obțineți o încercare gratuită a LogRocket astăzi.
Cuprins
- Pregătirea: planificare și valori
- Stabilirea obiectivelor realiste
- Definirea Mediului
- Optimizări ale activelor
- Construiți optimizări
- Optimizări de livrare
- Rețea, HTTP/2, HTTP/3
- Testare și monitorizare
- Victorii rapide
- Totul pe o singură pagină
- Descărcați Lista de verificare (PDF, Apple Pages, MS Word)
- Abonați-vă la buletinul nostru informativ prin e-mail pentru a nu rata următoarele ghiduri.
Optimizări de livrare
- Folosim
defer
pentru a încărca JavaScript critic în mod asincron?
Când utilizatorul solicită o pagină, browserul preia HTML-ul și construiește DOM-ul, apoi preia CSS-ul și construiește CSSOM-ul și apoi generează un arbore de randare prin potrivirea DOM-ului și CSSOM. Dacă trebuie rezolvat vreun JavaScript, browserul nu va începe redarea paginii până când nu este rezolvată, întârziind astfel randarea. În calitate de dezvoltatori, trebuie să spunem în mod explicit browserului să nu aștepte și să înceapă redarea paginii. Modul de a face acest lucru pentru scripturi este cu atributeledefer
șiasync
din HTML.În practică, se dovedește că este mai bine să folosiți
defer
în loc deasync
. Ah, care este din nou diferența ? Potrivit lui Steve Souders, odată ce sosesc scripturileasync
, acestea sunt executate imediat - de îndată ce scriptul este gata. Dacă acest lucru se întâmplă foarte repede, de exemplu când scriptul este deja în cache, poate bloca de fapt parserul HTML. Cudefer
, browserul nu execută scripturi până când HTML nu este analizat. Deci, dacă nu aveți nevoie de JavaScript pentru a executa înainte de a începe randarea, este mai bine să utilizațidefer
. De asemenea, mai multe fișiere asincrone se vor executa într-o ordine nedeterministă.Este demn de remarcat faptul că există câteva concepții greșite despre
async
șidefer
. Cel mai important,async
nu înseamnă că codul va rula ori de câte ori scriptul este gata; înseamnă că va rula ori de câte ori scripturile sunt gata și toate lucrările de sincronizare precedente sunt finalizate. În cuvintele lui Harry Roberts, „Dacă pui un scriptasync
după scripturile de sincronizare, scriptul tăuasync
este la fel de rapid ca cel mai lent script de sincronizare”.De asemenea, nu este recomandat să folosiți atât
async
, cât șidefer
. Browserele moderne acceptă ambele, dar ori de câte ori sunt folosite ambele atribute,async
va câștiga întotdeauna.Dacă doriți să vă scufundați în mai multe detalii, Milica Mihajlija a scris un ghid foarte detaliat despre Construirea mai rapidă a DOM-ului, intrând în detaliile analizei speculative, asincronizării și amânării.
- Încărcați leneș componentele scumpe cu IntersectionObserver și indicii de prioritate.
În general, este recomandat să încărcați leneș toate componentele costisitoare, cum ar fi JavaScript grele, videoclipuri, iframes, widget-uri și eventual imagini. Încărcarea leneră nativă este deja disponibilă pentru imagini și cadre iframe cu atributul deloading
(doar Chromium). Sub capotă, acest atribut amână încărcarea resursei până când ajunge la o distanță calculată de la fereastra de vizualizare.<!-- Lazy loading for images, iframes, scripts. Probably for images outside of the viewport. --> <img loading="lazy" ... /> <iframe loading="lazy" ... /> <!-- Prompt an early download of an asset. For critical images, eg hero images. --> <img loading="eager" ... /> <iframe loading="eager" ... />
Acest prag depinde de câteva lucruri, de la tipul de resursă de imagine preluată până la tipul de conexiune eficientă. Dar experimentele efectuate folosind Chrome pe Android sugerează că, pe 4G, 97,5% din imaginile de sub orificiu care sunt încărcate leneș au fost încărcate complet în 10 ms de când au devenit vizibile, așa că ar trebui să fie în siguranță.
Putem folosi, de asemenea, atributul de
importance
(high
saulow
) pe un element<script>
,<img>
sau<link>
(doar Blink). De fapt, este o modalitate excelentă de a deprioritiza imaginile din carusele, precum și de a re-prioritiza scripturile. Cu toate acestea, uneori s-ar putea să avem nevoie de un control un pic mai granular.<!-- When the browser assigns "High" priority to an image, but we don't actually want that. --> <img src="less-important-image.svg" importance="low" ... /> <!-- We want to initiate an early fetch for a resource, but also deprioritize it. --> <link rel="preload" importance="low" href="/script.js" as="script" />
Cea mai performantă modalitate de a face încărcare leneșă puțin mai sofisticată este utilizarea API-ului Intersection Observer, care oferă o modalitate de a observa asincron modificările în intersecția unui element țintă cu un element strămoș sau cu o fereastră de vizualizare a unui document de nivel superior. Practic, trebuie să creați un nou obiect
IntersectionObserver
, care primește o funcție de apel invers și un set de opțiuni. Apoi adăugăm o țintă de observat.Funcția de apel invers se execută atunci când ținta devine vizibilă sau invizibilă, așa că atunci când interceptează fereastra de vizualizare, puteți începe să efectuați unele acțiuni înainte ca elementul să devină vizibil. De fapt, avem un control granular asupra momentului în care ar trebui invocată callback-ul observatorului, cu
rootMargin
(marja în jurul rădăcinii) șithreshold
(un singur număr sau o matrice de numere care indică la ce procent din vizibilitatea țintei țintim).Alejandro Garcia Anglada a publicat un tutorial la îndemână despre cum să-l implementeze efectiv, Rahul Nanwani a scris o postare detaliată despre încărcarea leneșă a imaginilor din prim-plan și de fundal, iar Google Fundamentals oferă un tutorial detaliat despre încărcarea leneșă a imaginilor și a videoclipurilor cu Intersection Observer.
Îți amintești de povestirile direcționate de artă lecturi lungi cu obiecte în mișcare și lipicioase? Puteți implementa scrolltelling performant și cu Intersection Observer.
Verificați din nou ce altceva ați putea încărca leneș. Chiar și șirurile de traducere cu încărcare leneră și emoji-uri ar putea ajuta. Procedând astfel, Mobile Twitter a reușit să obțină o execuție JavaScript cu 80% mai rapidă din noua conductă de internaționalizare.
Totuși, un scurt cuvânt de precauție: merită remarcat faptul că încărcarea leneșă ar trebui să fie o excepție, mai degrabă decât o regulă. Probabil că nu este rezonabil să încărcați leneș ceva ce doriți ca oamenii să vadă rapid, de exemplu, imagini din pagina de produs, imagini eroi sau un script necesar pentru ca navigarea principală să devină interactivă.
- Încărcați imaginile progresiv.
Puteți chiar să duceți încărcarea leneșă la următorul nivel, adăugând încărcare progresivă a imaginii în paginile dvs. Similar cu Facebook, Pinterest, Medium și Wolt, puteți încărca mai întâi imagini de calitate scăzută sau chiar neclare, apoi, pe măsură ce pagina continuă să se încarce, înlocuiți-le cu versiuni de calitate completă utilizând tehnica BlurHash sau LQIP (Low Quality Image Placeholders). tehnică.Opiniile diferă dacă aceste tehnici îmbunătățesc sau nu experiența utilizatorului, dar cu siguranță îmbunătățesc timpul pentru First Contentful Paint. Îl putem automatiza chiar și utilizând SQIP care creează o versiune de calitate scăzută a unei imagini ca substituent SVG sau substituenți pentru imagini cu gradient cu gradienți liniari CSS.
Acești substituenți ar putea fi încorporați în HTML, deoarece se comprimă bine în mod natural cu metodele de comprimare a textului. În articolul său, Dean Hume a descris cum poate fi implementată această tehnică folosind Intersection Observer.
Da înapoi? Dacă browserul nu acceptă observatorul de intersecție, putem încărca leneș un polyfill sau încărcăm imaginile imediat. Și există chiar și o bibliotecă pentru el.
Vrei să devii mai fantezie? Puteți să vă urmăriți imaginile și să utilizați forme și margini primitive pentru a crea un substituent SVG ușor, să îl încărcați mai întâi și apoi să treceți de la imaginea vectorială cu substituent la imaginea bitmap (încărcată).
- Amânați redarea cu
content-visibility
?
Pentru un aspect complex, cu o mulțime de blocuri de conținut, imagini și videoclipuri, decodarea datelor și redarea pixelilor ar putea fi o operațiune destul de costisitoare - mai ales pe dispozitivele low-end. Cucontent-visibility: auto
, putem solicita browserului să ignore aspectul copiilor în timp ce containerul se află în afara ferestrei de vizualizare.De exemplu, puteți sări peste redarea subsolului și a secțiunilor târzii de la încărcarea inițială:
footer { content-visibility: auto; contain-intrinsic-size: 1000px; /* 1000px is an estimated height for sections that are not rendered yet. */ }
Rețineți că vizibilitatea conținutului: automat; se comportă ca preaplin: ascuns; , dar îl puteți remedia aplicând
padding-left
șipadding-right
în loc demargin-left: auto;
,margin-right: auto;
și o lățime declarată. Umplutura permite, practic, elementelor să depășească caseta de conținut și să intre în caseta de umplutură fără a părăsi modelul de cutie în întregime și a fi tăiate.De asemenea, rețineți că ați putea introduce niște CLS atunci când conținutul nou va fi redat în cele din urmă, așa că este o idee bună să utilizați
contain-intrinsic-size
cu un substituent dimensionat corespunzător ( mulțumesc, Una! ).Thijs Terluin are mult mai multe detalii despre ambele proprietăți și despre modul în care browser-ul calculează
contain-intrinsic-size
a conținutului, Malte Ubl vă arată cum o puteți calcula și un scurt explicator video de Jake și Surma explică cum funcționează totul.Și dacă aveți nevoie să obțineți un pic mai granular, cu CSS Containment, puteți sări manual aspectul, stilul și lucrările de vopsire pentru descendenții unui nod DOM dacă aveți nevoie doar de dimensiune, aliniere sau stiluri calculate pentru alte elemente - sau elementul este în prezent în afara pânzei.
- Amânați decodarea cu
decoding="async"
?
Uneori, conținutul apare în afara ecranului, dar dorim să ne asigurăm că este disponibil atunci când clienții au nevoie de el - în mod ideal, nu blocând nimic din calea critică, ci decodând și redând asincron. Putem folosidecoding="async"
pentru a acorda browserului permisiunea de a decoda imaginea din firul principal, evitând impactul utilizatorului al timpului CPU utilizat pentru a decoda imaginea (prin Malte Ubl):<img decoding="async" … />
Alternativ, pentru imaginile în afara ecranului, putem afișa mai întâi un substituent, iar când imaginea se află în fereastra de vizualizare, folosind IntersectionObserver, declanșăm un apel de rețea pentru ca imaginea să fie descărcată în fundal. De asemenea, putem amâna randarea până la decodare cu img.decode() sau putem descărca imaginea dacă API-ul Image Decode nu este disponibil.
Când redăm imaginea, putem folosi, de exemplu, animații cu fade-in. Katie Hempenius și Addy Osmani împărtășesc mai multe informații în discursul lor Viteză la scară: Sfaturi și trucuri de performanță web din tranșee.
- Generați și serviți CSS critic?
Pentru a vă asigura că browserele încep să redeze pagina dvs. cât mai repede posibil, a devenit o practică obișnuită să colectați toate CSS-urile necesare pentru a începe redarea primei părți vizibile a paginii (cunoscută sub numele de „CSS critic” sau „CSS de deasupra paginii”. ") și includeți-l în linie în<head>
a paginii, reducând astfel călătoriile dus-întors. Datorită dimensiunii limitate a pachetelor schimbate în timpul fazei de pornire lentă, bugetul dumneavoastră pentru CSS critic este de aproximativ 14KB.Dacă treceți mai departe, browserul va avea nevoie de călătorii dus-întors suplimentare pentru a prelua mai multe stiluri. CriticalCSS și Critical vă permit să scoateți CSS critic pentru fiecare șablon pe care îl utilizați. Totuși, din experiența noastră, niciun sistem automat nu a fost vreodată mai bun decât colectarea manuală a CSS-urilor critice pentru fiecare șablon și, într-adevăr, aceasta este abordarea la care am revenit recent.
Puteți apoi să integrați CSS critic și să încărcați leneș restul cu pluginul Critters Webpack. Dacă este posibil, luați în considerare utilizarea abordării condiționale în linie utilizată de Filament Group sau convertiți din mers codul în linie în active statice.
Dacă în prezent încărcați CSS complet asincron cu biblioteci precum loadCSS, nu este chiar necesar. Cu
media="print"
, puteți păcăli browserul să preia CSS-ul în mod asincron, dar să se aplice în mediul ecranului odată ce se încarcă. ( Mulțumesc, Scott! )<!-- Via Scott Jehl. https://www.filamentgroup.com/lab/load-css-simpler/ --> <!-- Load CSS asynchronously, with low priority --> <link rel="stylesheet" href="full.css" media="print" onload="this.media='all'" />
Atunci când colectați toate CSS-urile esențiale pentru fiecare șablon, este obișnuit să explorați numai zona „de deasupra pliului”. Cu toate acestea, pentru layout-uri complexe, ar putea fi o idee bună să includeți și bazele aspectului pentru a evita costurile masive de recalculare și revopsire, rănind astfel scorul Core Web Vitals.
Ce se întâmplă dacă un utilizator primește o adresă URL care trimite direct la mijlocul paginii, dar CSS-ul nu a fost încă descărcat? În acest caz, a devenit obișnuit să se ascundă conținut necritic, de exemplu cu
opacity: 0;
în CSS inline șiopacity: 1
în fișierul CSS complet și afișați-l când CSS este disponibil. Totuși, are un dezavantaj major , deoarece utilizatorii cu conexiuni lente s-ar putea să nu poată citi niciodată conținutul paginii. De aceea, este mai bine să păstrați întotdeauna conținutul vizibil, chiar dacă este posibil să nu fie stilat corespunzător.Punerea CSS-ului critic (și a altor active importante) într-un fișier separat pe domeniul rădăcină are avantaje, uneori chiar mai mult decât inline, datorită stocării în cache. Chrome deschide în mod speculativ o a doua conexiune HTTP la domeniul rădăcină atunci când solicită pagina, ceea ce elimină necesitatea unei conexiuni TCP pentru a prelua acest CSS. Aceasta înseamnă că puteți crea un set de fișiere -CSS critice (de exemplu critical-homepage.css , critical-product-page.css etc.) și le puteți servi de la rădăcină, fără a fi nevoie să le introduceți. ( Multumesc, Philip! )
Un cuvânt de precauție: cu HTTP/2, CSS-ul critic ar putea fi stocat într-un fișier CSS separat și livrat printr-un push de server fără a umfla HTML. Problema este că împingerea serverului a fost deranjantă cu multe probleme și condiții de cursă în browsere. Nu a fost niciodată acceptat în mod consecvent și a avut unele probleme de cache (vezi diapozitivul 114 de la prezentarea lui Hooman Beheshti).
Efectul ar putea, de fapt, să fie negativ și să umfle tampoanele de rețea, împiedicând livrarea cadrelor autentice din document. Deci nu a fost foarte surprinzător că, deocamdată, Chrome plănuiește să elimine suportul pentru Server Push.
- Experimentați cu regruparea regulilor dvs. CSS.
Ne-am obișnuit cu CSS critic, dar există câteva optimizări care ar putea depăși asta. Harry Roberts a efectuat o cercetare remarcabilă cu rezultate destul de surprinzătoare. De exemplu, ar putea fi o idee bună să împărțiți fișierul CSS principal în interogări media individuale. În acest fel, browserul va prelua CSS critic cu prioritate mare și orice altceva cu prioritate scăzută - complet în afara căii critice.De asemenea, evitați să plasați
<link rel="stylesheet" />
înaintea fragmentelorasync
. Dacă scripturile nu depind de foile de stil, luați în considerare plasarea scripturilor de blocare deasupra stilurilor de blocare. Dacă o fac, împărțiți acel JavaScript în două și încărcați-l pe fiecare parte a CSS-ului dvs.Scott Jehl a rezolvat o altă problemă interesantă prin memorarea în cache a unui fișier CSS inline cu un lucrător de service, o problemă comună cunoscută dacă utilizați CSS critic. Practic, adăugăm un atribut ID pe elementul de
style
, astfel încât să fie ușor de găsit folosind JavaScript, apoi o mică bucată de JavaScript găsește acel CSS și folosește API-ul Cache pentru a-l stoca într-un cache local al browserului (cu un tip de conținut detext/css
) pentru utilizare pe paginile următoare. Pentru a evita introducerea pe paginile ulterioare și, în schimb, facem referire la activele stocate în cache în exterior, apoi setăm un cookie la prima vizită pe un site. Voila!Merită remarcat faptul că stilul dinamic poate fi și costisitor, dar de obicei numai în cazurile în care te bazezi pe sute de componente compuse redate concomitent. Deci, dacă utilizați CSS-in-JS, asigurați-vă că biblioteca dvs. CSS-in-JS optimizează execuția atunci când CSS-ul dvs. nu are dependențe de temă sau elemente de recuzită și nu supracompuneți componente cu stil . Aggelos Arvanitakis oferă mai multe informații despre costurile de performanță ale CSS-in-JS.
- Transmiteți răspunsuri?
Adesea uitate și neglijate, fluxurile oferă o interfață pentru citirea sau scrierea unor bucăți asincrone de date, dintre care doar un subset ar putea fi disponibil în memorie la un moment dat. Practic, ele permit paginii care a făcut cererea inițială să înceapă să lucreze cu răspunsul de îndată ce prima bucată de date este disponibilă și utilizează parsere care sunt optimizate pentru streaming pentru a afișa progresiv conținutul.Am putea crea un flux din mai multe surse. De exemplu, în loc să serviți un shell UI gol și să lăsați JavaScript să-l populeze, puteți lăsa lucrătorul de servicii să construiască un flux în care shell-ul provine dintr-un cache, dar corpul provine din rețea. După cum a remarcat Jeff Posnick, dacă aplicația dvs. web este alimentată de un CMS care redă HTML prin împletire a șabloanelor parțiale, modelul respectiv se traduce direct în utilizarea răspunsurilor în flux, cu logica de șabloane replicată în serviciul de lucru în loc de server. Articolul The Year of Web Streams al lui Jake Archibald evidențiază cum exact l-ați putea construi. Creșterea performanței este destul de vizibilă.
Un avantaj important al transmiterii întregului răspuns HTML este că HTML redat în timpul solicitării inițiale de navigare poate profita din plin de analizatorul HTML de streaming al browserului. Bucățile de HTML care sunt inserate într-un document după ce pagina s-a încărcat (cum este obișnuit în cazul conținutului populat prin JavaScript) nu pot profita de această optimizare.
Suport pentru browser? Încă ajung acolo cu suport parțial în Chrome, Firefox, Safari și Edge, care acceptă API și Service Workers, care sunt acceptate în toate browserele moderne. Și dacă te simți din nou aventuros, poți verifica o implementare experimentală a cererilor de streaming, care îți permite să începi să trimiți cererea în timp ce generezi corpul. Disponibil în Chrome 85.
- Luați în considerare să vă faceți conexiunea componentelor.
Datele pot fi costisitoare și, cu sarcina utilă în creștere, trebuie să respectăm utilizatorii care aleg să opteze pentru economisirea datelor în timp ce accesează site-urile sau aplicațiile noastre. Antetul cererii de indiciu pentru client Save-Data ne permite să personalizăm aplicația și sarcina utilă pentru utilizatorii cu costuri limitate și performanță.De fapt, puteți rescrie solicitările pentru imagini cu DPI ridicat în imagini cu DPI scăzut, elimina fonturile web, efectele de paralaxă fanteziste, previzualizați miniaturile și derularea infinită, dezactivați redarea automată a videoclipurilor, împingerea serverului, reduceți numărul de elemente afișate și reduceți calitatea imaginii sau chiar schimbați modul în care livrați marcajul. Tim Vereecke a publicat un articol foarte detaliat despre strategiile de economisire a datelor, oferind multe opțiuni pentru salvarea datelor.
Cine folosește
save-data
, s-ar putea să vă întrebați? 18% dintre utilizatorii Android Chrome la nivel global au Modul simplificat activat (cuSave-Data
activată), iar numărul este probabil mai mare. Conform cercetărilor lui Simon Hearne, rata de înscriere este cea mai mare pe dispozitivele mai ieftine, dar există o mulțime de valori aberante. De exemplu: utilizatorii din Canada au o rată de înscriere de peste 34% (comparativ cu ~7% în SUA), iar utilizatorii de pe cel mai recent flagship Samsung au o rată de înscriere de aproape 18% la nivel global.Cu modul
Save-Data
activat, Chrome Mobile va oferi o experiență optimizată, adică o experiență web proxy cu scripturi amânate ,font-display: swap
și încărcare leneră forțată. Este mai sensibil să construiți experiența pe cont propriu decât să vă bazați pe browser pentru a face aceste optimizări.În prezent, antetul este acceptat numai în Chromium, pe versiunea Android a Chrome sau prin extensia Data Saver pe un dispozitiv desktop. În cele din urmă, puteți utiliza și API-ul Network Information pentru a furniza module JavaScript costisitoare, imagini de înaltă rezoluție și videoclipuri bazate pe tipul de rețea. Network Information API și în special
navigator.connection.effectiveType
utilizează valorileRTT
,downlink
,effectiveType
(și altele) pentru a oferi o reprezentare a conexiunii și a datelor pe care utilizatorii le pot gestiona.În acest context, Max Bock vorbește despre componentele conștiente de conexiune, iar Addy Osmani vorbește despre servirea modulelor adaptive. De exemplu, cu React, am putea scrie o componentă care se redă diferit pentru diferite tipuri de conexiune. După cum a sugerat Max, o componentă
<Media />
dintr-un articol de știri ar putea scoate:-
Offline
: un substituent cu textalt
, -
2G
/ modulsave-data
: o imagine cu rezoluție scăzută, -
3G
pe ecran non-Retina: o imagine cu rezoluție medie, -
3G
pe ecranele Retina: imagine Retina de înaltă rezoluție, -
4G
: un videoclip HD.
Dean Hume oferă o implementare practică a unei logici similare folosind un lucrător de service. Pentru un videoclip, am putea afișa implicit un poster video și apoi să afișăm pictograma „Redare”, precum și shell-ul playerului video, metadatele videoclipului etc. pe conexiuni mai bune. Ca o alternativă pentru browserele care nu acceptă, am putea asculta evenimentul
canplaythrough
și am putea folosiPromise.race()
pentru a opri încărcarea sursei dacă evenimentulcanplaythrough
nu se declanșează în 2 secunde.Dacă doriți să vă aprofundați puțin, iată câteva resurse pentru a începe:
- Addy Osmani arată cum să implementați servirea adaptivă în React.
- React Adaptive Loading Hooks & Utilities oferă fragmente de cod pentru React,
- Netanel Basel explorează componentele conștiente de conexiune în Angular,
- Theodore Vorilas împărtășește cum funcționează Servirea componentelor adaptive folosind API-ul de informații de rețea în Vue.
- Umar Hansa arată cum să descărcați/executați JavaScript în mod selectiv.
-
- Luați în considerare posibilitatea de a face componentele dispozitivului conștient de memorie.
Totuși, conexiunea la rețea ne oferă o singură perspectivă asupra contextului utilizatorului. Mergând mai departe, puteți, de asemenea, să ajustați dinamic resursele în funcție de memoria disponibilă a dispozitivului, cu API-ul Device Memory.navigator.deviceMemory
returnează câtă memorie RAM are dispozitivul în gigaocteți, rotunjită la cea mai apropiată putere de doi. API-ul include, de asemenea, un antet de sugestii pentru client,Device-Memory
, care raportează aceeași valoare.Bonus : Umar Hansa arată cum să amânați scripturile scumpe cu importuri dinamice pentru a schimba experiența pe baza memoriei dispozitivului, a conectivității la rețea și a concurenței hardware.
- Încălziți conexiunea pentru a accelera livrarea.
Folosiți indicii de resurse pentru a economisi timp ladns-prefetch
(care efectuează o căutare DNS în fundal),preconnect
(care solicită browserului să pornească strângere de mână de conectare (DNS, TCP, TLS) în fundal),prefetch
(care solicită browserului) pentru a solicita o resursă) șipreload
(care preface resursele fără a le executa, printre altele). Bine acceptat în browserele moderne, cu suport pentru Firefox în curând.Îți amintești de pre-
prerender
? Sugestia de resurse folosită pentru a solicita browserului să construiască întreaga pagină în fundal pentru următoarea navigare. Problemele de implementare au fost destul de problematice, variind de la o amprentă uriașă a memoriei și utilizarea lățimii de bandă până la accesări de analiză și afișări de anunțuri multiple înregistrate.Deloc surprinzător, a fost depreciat, dar echipa Chrome l-a adus înapoi ca mecanism NoState Prefetch. De fapt, Chrome tratează indicația de pre-rendare ca un
prerender
Prefetch, așa că îl putem folosi și astăzi. Așa cum explică Katie Hempenius în acel articol, „ca și prerendarea, NoState Prefetch preia resursele în avans ; dar, spre deosebire de prerendarea, nu execută JavaScript și nici nu redă nicio parte a paginii în avans”.NoState Prefetch folosește numai ~45MiB de memorie, iar subresursele care sunt preluate vor fi preluate cu o Prioritate de rețea
IDLE
. Începând cu Chrome 69, NoState Prefetch adaugă antetul Scop: Prefetch la toate solicitările pentru a le face să se distingă de navigarea normală.De asemenea, fiți atenți la alternativele și portalurile de pre-rendare, un nou efort către pre-rendarea conștientă de confidențialitate, care va oferi
preview
în interior a conținutului pentru navigare fără întreruperi.Utilizarea sugestiilor de resurse este probabil cea mai ușoară modalitate de a crește performanța și funcționează într-adevăr bine. Când să folosești ce? După cum a explicat Addy Osmani, este rezonabil să preîncărcăm resurse despre care știm că sunt foarte probabil să fie utilizate pe pagina curentă și pentru navigarea viitoare peste mai multe granițe de navigare, de exemplu pachetele Webpack necesare pentru paginile pe care utilizatorul nu le-a vizitat încă.
Articolul lui Addy despre „Încărcarea priorităților în Chrome” arată modul în care Chrome interpretează exact sugestiile de resurse, așa că, odată ce ați decis ce elemente sunt esențiale pentru randare, le puteți acorda prioritate ridicată. Pentru a vedea cum sunt prioritizate solicitările dvs., puteți activa o coloană „prioritate” în tabelul de solicitări de rețea Chrome DevTools (precum și Safari).
De cele mai multe ori în aceste zile, vom folosi cel puțin
preconnect
șidns-prefetch
și vom fi precauți când folosimprefetch
,preload
șiprerender
. Rețineți că, chiar și cupreconnect
șidns-prefetch
, browserul are o limită a numărului de gazde la care se va căuta/conecta în paralel, așa că este un pariu sigur să le comandați în funcție de prioritate ( mulțumesc Philip Tellis! ).Deoarece fonturile sunt de obicei elemente importante pe o pagină, uneori este o idee bună să solicitați browserului să descarce fonturi critice cu
preload
. Cu toate acestea, verificați dacă ajută într-adevăr la performanță, deoarece există un puzzle de priorități atunci când preîncărcați fonturile: deoarecepreload
este văzută ca fiind de mare importanță, poate să depășească și mai multe resurse critice, cum ar fi CSS critic. ( mulțumesc, Barry! )<!-- Loading two rendering-critical fonts, but not all their weights. --> <!-- crossorigin="anonymous" is required due to CORS. Without it, preloaded fonts will be ignored. https://github.com/w3c/preload/issues/32 via https://twitter.com/iamakulov/status/1275790151642423303 --> <link rel="preload" as="font" href="Elena-Regular.woff2" type="font/woff2" crossorigin="anonymous" media="only screen and (min-width: 48rem)" /> <link rel="preload" as="font" href="Mija-Bold.woff2" type="font/woff2" crossorigin="anonymous" media="only screen and (min-width: 48rem)" />
<!-- Loading two rendering-critical fonts, but not all their weights. --> <!-- crossorigin="anonymous" is required due to CORS. Without it, preloaded fonts will be ignored. https://github.com/w3c/preload/issues/32 via https://twitter.com/iamakulov/status/1275790151642423303 --> <link rel="preload" as="font" href="Elena-Regular.woff2" type="font/woff2" crossorigin="anonymous" media="only screen and (min-width: 48rem)" /> <link rel="preload" as="font" href="Mija-Bold.woff2" type="font/woff2" crossorigin="anonymous" media="only screen and (min-width: 48rem)" />
Deoarece
<link rel="preload">
acceptă un atributmedia
, puteți alege să descărcați selectiv resurse pe baza regulilor de interogare@media
, așa cum se arată mai sus.În plus, putem folosi atributele
imagesrcset
șiimagesizes
pentru a preîncărca mai repede imaginile eroilor descoperite târziu sau orice imagini care sunt încărcate prin JavaScript, de exemplu postere de filme:<!-- Addy Osmani. https://addyosmani.com/blog/preload-hero-images/ --> <link rel="preload" as="image" href="poster.jpg" image image>
<!-- Addy Osmani. https://addyosmani.com/blog/preload-hero-images/ --> <link rel="preload" as="image" href="poster.jpg" image image>
De asemenea, putem preîncărca JSON ca fetch , deci este descoperit înainte ca JavaScript să-l solicite:
<!-- Addy Osmani. https://addyosmani.com/blog/preload-hero-images/ --> <link rel="preload" as="fetch" href="foo.com/api/movies.json" crossorigin>
De asemenea, am putea încărca JavaScript dinamic, eficient pentru execuția leneșă a scriptului.
/* Adding a preload hint to the head */ var preload = document.createElement("link"); link.href = "myscript.js"; link.rel = "preload"; link.as = "script"; document.head.appendChild(link); /* Injecting a script when we want it to execute */ var script = document.createElement("script"); script.src = "myscript.js"; document.body.appendChild(script);
Câteva probleme de reținut:
preload
este bună pentru a muta timpul de pornire a descărcarii unui activ mai aproape de solicitarea inițială, dar activele preîncărcate ajung în memoria cache care este legată de pagina care face solicitarea.preload
se joacă bine cu cache-ul HTTP: o solicitare de rețea nu este niciodată trimisă dacă elementul este deja acolo în cache-ul HTTP.Prin urmare, este util pentru resursele descoperite târziu, imaginile eroice încărcate prin
background-image
, integrarea CSS-ului critic (sau JavaScript) și preîncărcarea restului CSS (sau JavaScript).O etichetă de
preload
poate iniția o preîncărcare numai după ce browserul a primit codul HTML de la server și analizatorul anticipat a găsit eticheta depreload
. Preîncărcarea prin antetul HTTP ar putea fi puțin mai rapidă, deoarece nu trebuie să așteptăm ca browserul să analizeze HTML pentru a porni cererea (este dezbătut totuși).Sfaturile timpurii vă vor ajuta și mai mult, permițând preîncărcarea să intervină chiar înainte ca anteturile de răspuns pentru HTML să fie trimise (pe foaia de parcurs în Chromium, Firefox). În plus, Sfaturile de prioritate ne vor ajuta să indicăm prioritățile de încărcare pentru scripturi.
Atenție : dacă utilizați
preload
,as
trebuie definit sau nimic nu se încarcă, plus fonturile preîncărcate fără atributulcrossorigin
se vor prelua dublu. Dacă utilizațiprefetch
, aveți grijă la problemele cu antetulAge
în Firefox.
- Utilizați lucrători de service pentru stocarea în cache și pentru rețelele de rezervă.
Nicio optimizare a performanței într-o rețea nu poate fi mai rapidă decât un cache stocat local pe computerul unui utilizator (există, totuși, excepții). Dacă site-ul dvs. rulează prin HTTPS, putem stoca în cache activele statice într-un cache de lucrător al serviciului și putem stoca alternative offline (sau chiar pagini offline) și le putem prelua de pe computerul utilizatorului, în loc să mergem în rețea.După cum a sugerat Phil Walton, împreună cu lucrătorii de servicii, putem trimite încărcături utile HTML mai mici prin generarea programatică a răspunsurilor noastre. Un lucrător al serviciului poate solicita de la server doar minimumul de date de care are nevoie (de exemplu, un conținut HTML parțial, un fișier Markdown, date JSON etc.), apoi poate transforma în mod programatic acele date într-un document HTML complet. Deci, odată ce un utilizator vizitează un site și lucrătorul de service este instalat, utilizatorul nu va mai solicita niciodată o pagină HTML completă. Impactul asupra performanței poate fi destul de impresionant.
Suport pentru browser? Lucrătorii de servicii sunt susținuți pe scară largă, iar rețeaua de rezervă este oricum. Ajută la creșterea performanței ? Da, da. Și este din ce în ce mai bine, de exemplu, cu Background Fetch, care permite încărcările/descărcările în fundal și prin intermediul unui service worker.
Există o serie de cazuri de utilizare pentru un lucrător de servicii. De exemplu, puteți implementa funcția „Salvare pentru offline”, gestionați imaginile rupte, introduceți mesaje între file sau oferi diferite strategii de stocare în cache în funcție de tipurile de solicitare. În general, o strategie de încredere obișnuită este să stocați shell-ul aplicației în memoria cache a lucrătorului de servicii împreună cu câteva pagini critice, cum ar fi pagina offline, prima pagină și orice altceva care ar putea fi important în cazul dvs.
Există totuși câteva probleme de reținut. Cu un lucrător de service, trebuie să fim atenți la solicitările de interval în Safari (dacă utilizați Workbox pentru un lucrător de service, acesta are un modul de solicitare de interval). Dacă ați dat vreodată peste
DOMException: Quota exceeded.
eroare în consola browserului, apoi consultați articolul lui Gerardo Când 7KB este egal cu 7MB.Așa cum scrie Gerardo, „Dacă construiți o aplicație web progresivă și întâmpinați stocare cache umflată atunci când lucrătorul dvs. de servicii memorează în cache activele statice furnizate de la CDN-uri, asigurați-vă că există antetul de răspuns CORS adecvat pentru resursele de origine încrucișată, nu stocați în cache răspunsurile opace. împreună cu lucrătorul dvs. de servicii, în mod neintenționat, activați elementele de imagine cu origini încrucișate în modul CORS adăugând atributul
crossorigin
la eticheta<img>
.”Există o mulțime de resurse excelente pentru a începe cu lucrătorii de service:
- Service Worker Mindset, care vă ajută să înțelegeți cum lucrează lucrătorii din service în culise și lucruri de înțeles atunci când construiți unul.
- Chris Ferdinandi oferă o serie grozavă de articole despre lucrătorii de servicii, explicând cum să creați aplicații offline și acoperind o varietate de scenarii, de la salvarea offline a paginilor vizualizate recent până la setarea unei date de expirare pentru articolele dintr-un cache pentru lucrătorii de service.
- Capcanele și cele mai bune practici pentru lucrătorii de service, cu câteva sfaturi despre domeniul de aplicare, întârzierea înregistrării unui lucrător de service și memorarea în cache a lucrătorului în service.
- Serial grozav de Ire Aderinokun pe „Offline First” cu Service Worker, cu o strategie de precaching a shell-ului aplicației.
- Service Worker: o introducere cu sfaturi practice despre cum să utilizați service worker pentru experiențe bogate offline, sincronizări periodice în fundal și notificări push.
- Merită întotdeauna să vă referiți la cartea de bucate offline a lui Jake Archibald, cu o serie de rețete despre cum să vă coaceți propriul lucrător de service.
- Workbox este un set de biblioteci de lucrători ai serviciului construit special pentru construirea de aplicații web progresive.
- Executați lucrători de server pe CDN/Edge, de exemplu pentru testarea A/B?
În acest moment, suntem destul de obișnuiți să rulăm lucrători de servicii pe client, dar cu CDN-urile care le implementează pe server, le-am putea folosi pentru a îmbunătăți performanța și pe margine.De exemplu, în testele A/B, când HTML trebuie să-și modifice conținutul pentru diferiți utilizatori, am putea folosi Service Workers pe serverele CDN pentru a gestiona logica. De asemenea, am putea transmite rescrierea HTML pentru a accelera site-urile care folosesc Fonturi Google.
- Optimizați performanța de redare.
Ori de câte ori aplicația este lentă, este vizibilă imediat. Așa că trebuie să ne asigurăm că nu există nicio întârziere la derularea paginii sau când un element este animat și că atingeți constant 60 de cadre pe secundă. Dacă acest lucru nu este posibil, atunci este de preferat ca cel puțin să faceți consecvența cadrelor pe secundă față de un interval mixt de 60 până la 15. Utilizațiwill-change
CSS pentru a informa browserul despre ce elemente și proprietăți se vor schimba.Ori de câte ori vă confruntați, depanați revopsirile inutile în DevTools:
- Măsurați performanța de redare la timpul de execuție. Consultați câteva sfaturi utile despre cum să le înțelegeți.
- Pentru a începe, consultați cursul gratuit Udacity al lui Paul Lewis despre optimizarea redării browserului și articolul lui Georgy Marchuk despre pictarea browserului și considerente pentru performanța web.
- Activați Paint Flashing în „Mai multe instrumente → Redare → Paint Flashing” din Firefox DevTools.
- În React DevTools, bifați „Evidențiați actualizările” și activați „Înregistrați de ce este randată fiecare componentă”,
- De asemenea, puteți utiliza De ce ați randat, astfel încât, atunci când o componentă este redată din nou, un flash vă va anunța despre modificare.
Folosiți un aspect de zidărie? Rețineți că s-ar putea să construiți un aspect Masonry doar cu grila CSS, foarte curând.
Dacă doriți să aprofundați subiectul, Nolan Lawson a împărtășit trucuri pentru a măsura cu exactitate performanța aspectului în articolul său, iar Jason Miller a sugerat și tehnici alternative. Avem și un mic articol al lui Sergey Chikuyonok despre cum să obțineți animația GPU corect.
Notă : modificările aduse straturilor compuse din GPU sunt cele mai puțin costisitoare, așa că dacă puteți scăpa declanșând numai compunerea prin
opacity
șitransform
, veți fi pe drumul cel bun. Anna Migas a oferit o mulțime de sfaturi practice în discursul ei despre Debugging UI Rendering Performance, de asemenea. Și pentru a înțelege cum să depanați performanța vopselei în DevTools, verificați videoclipul de audit al performanței vopselei al lui Umar. - Ați optimizat pentru performanța percepută?
Deși secvența modului în care apar componentele pe pagină și strategia modului în care deservim activele browserului contează, nu ar trebui să subestimăm și rolul performanței percepute. Conceptul tratează aspectele psihologice ale așteptării, practic menținând clienții ocupați sau implicați în timp ce altceva se întâmplă. Acolo intră în joc managementul percepției, pornirea preventivă, finalizarea timpurie și managementul toleranței.Ce înseamnă toate acestea? În timpul încărcării activelor, putem încerca să fim întotdeauna cu un pas înaintea clientului, astfel încât experiența să fie rapidă, în timp ce se întâmplă destul de multe în fundal. Pentru a menține clientul implicat, putem testa ecrane schelete (demo de implementare) în loc de indicatori de încărcare, putem adăuga tranziții/animații și, practic, înșela UX-ul când nu mai este nimic de optimizat.
În studiul lor de caz despre The Art of UI Skeletons, Kumar McMillan împărtășește câteva idei și tehnici despre cum să simuleze liste dinamice, text și ecranul final, precum și cum să ia în considerare gândirea scheletului cu React.
Atenție totuși: ecranele scheletului ar trebui testate înainte de implementare, deoarece unele teste au arătat că ecranele scheletului pot funcționa cel mai rău după toate valorile.
- Preveniți schimbările de aspect și revopsiți?
În domeniul performanței percepute, probabil, una dintre experiențele cele mai perturbatoare este schimbarea aspectului sau refluxurile , cauzate de imagini și videoclipuri redimensionate, fonturi web, anunțuri injectate sau scripturi descoperite târziu care populează componente cu conținut real. Ca rezultat, un client ar putea începe să citească un articol doar pentru a fi întrerupt de un salt de aspect deasupra zonei de lectură. Experiența este adesea abruptă și destul de dezorientatoare: și acesta este probabil un caz de încărcare a priorităților care trebuie reconsiderate.Comunitatea a dezvoltat câteva tehnici și soluții alternative pentru a evita refluxurile. În general, este o idee bună să evitați inserarea de conținut nou deasupra conținutului existent , cu excepția cazului în care se întâmplă ca răspuns la o interacțiune a utilizatorului. Setați întotdeauna atributele de lățime și înălțime pe imagini, astfel încât browserele moderne alocă caseta și rezervă spațiul în mod implicit (Firefox, Chrome).
Atât pentru imagini, cât și pentru videoclipuri, putem folosi un substituent SVG pentru a rezerva caseta de afișare în care va apărea media. Aceasta înseamnă că zona va fi rezervată corect atunci când trebuie să-i mențineți și raportul de aspect. De asemenea, putem folosi substituenți sau imagini de rezervă pentru anunțuri și conținut dinamic, precum și pre-alocați spații de aspect.
În loc de încărcarea leneră a imaginilor cu scripturi externe, luați în considerare utilizarea încărcării leneșe native sau a încărcării leneșe hibride atunci când încărcăm un script extern numai dacă încărcarea leneră nativă nu este acceptată.
După cum s-a menționat mai sus, grupați întotdeauna revopsele fonturilor web și treceți de la toate fonturile alternative la toate fonturile web simultan - asigurați-vă doar că comutatorul nu este prea brusc, ajustând înălțimea liniilor și distanța dintre fonturi cu font-style-matcher .
Pentru a suprascrie valorile fonturilor pentru un font alternativ pentru a emula un font web, putem folosi descriptori @font-face pentru a înlocui valorile fontului (demo, activat în Chrome 87). (Rețineți că ajustările sunt complicate cu stivele complicate de fonturi.)
Pentru CSS târziu, ne putem asigura că CSS-ul critic pentru aspect este introdus în antetul fiecărui șablon. Mai mult decât atât: pentru paginile lungi, când este adăugată bara de defilare verticală, se deplasează conținutul principal cu 16 pixeli la stânga. Pentru a afișa o bară de derulare mai devreme, putem adăuga
overflow-y: scroll
onhtml
pentru a impune o bară de defilare la prima vopsea. Acesta din urmă ajută, deoarece barele de defilare pot provoca modificări non-triviale ale aspectului din cauza refluxării conținutului de deasupra pliului atunci când lățimea se schimbă. Totuși, ar trebui să se întâmple mai ales pe platforme cu bare de defilare fără suprapunere, cum ar fi Windows. Dar:position: sticky
, deoarece acele elemente nu vor derula niciodată din container.Dacă aveți de-a face cu anteturi care devin fixe sau lipicioase, poziționate în partea de sus a paginii pe defilare, rezervați spațiu pentru antet atunci când acesta devine blocat, de exemplu, cu un element substituent sau
margin-top
pe conținut. O excepție ar trebui să fie bannerele de consimțământ pentru cookie-uri care nu ar trebui să aibă impact asupra CLS, dar uneori o fac: depinde de implementare. Există câteva strategii și concluzii interesante în acest thread de Twitter.Pentru o componentă a filei care ar putea include diverse cantități de texte, puteți preveni schimbările de aspect cu stivele de grilă CSS. Prin plasarea conținutului fiecărei file în aceeași zonă de grilă și ascunderea uneia dintre ele odată, ne putem asigura că containerul ia întotdeauna înălțimea elementului mai mare, astfel încât să nu apară schimbări de layout.
Ah, și bineînțeles, derularea infinită și „Încărcați mai mult” pot provoca și schimbări de aspect, dacă există conținut sub listă (de exemplu, subsol). Pentru a îmbunătăți CLS, rezervați suficient spațiu pentru conținutul care ar fi încărcat înainte ca utilizatorul să defileze la acea parte a paginii, eliminați subsolul sau orice elemente DOM din partea de jos a paginii care ar putea fi împins în jos prin încărcarea conținutului. De asemenea, preluați în prealabil datele și imaginile pentru conținutul de mai jos, astfel încât, în momentul în care un utilizator derulează atât de departe, acesta este deja acolo. Puteți utiliza biblioteci de virtualizare a listelor, cum ar fi react-window, pentru a optimiza și liste lungi ( mulțumesc, Addy Osmani! ).
Pentru a vă asigura că impactul refluxurilor este limitat, măsurați stabilitatea aspectului cu API-ul Layout Instability. Cu acesta, puteți calcula scorul Cumulative Layout Shift ( CLS ) și îl puteți include ca o cerință în testele dvs., astfel încât oricând apare o regresie, puteți să o urmăriți și să o remediați.
Pentru a calcula scorul deplasării aspectului, browserul analizează dimensiunea ferestrei de vizualizare și mișcarea elementelor instabile în fereastra de vizualizare între două cadre randate. În mod ideal, scorul ar fi aproape de
0
. Există un ghid grozav de Milica Mihajlija și Philip Walton despre ce este CLS și cum să-l măsoare. Este un bun punct de plecare pentru a măsura și menține performanța percepută și pentru a evita întreruperea, în special pentru sarcinile esențiale pentru afaceri.Sfat rapid : pentru a descoperi ce a cauzat o schimbare de aspect în DevTools, puteți explora schimbările de aspect în „Experiență” din Panoul de performanță.
Bonus : dacă doriți să reduceți reflow-urile și revopsele, consultați ghidul lui Charis Theodoulou pentru Minimizarea DOM Reflow/Layout Thrashing și lista lui Paul Irish de Ce forțează layout-ul/reflow, precum și CSSTriggers.com, un tabel de referință cu proprietățile CSS care declanșează aspectul, pictura și compoziție.
Cuprins
- Pregătirea: planificare și valori
- Stabilirea obiectivelor realiste
- Definirea Mediului
- Optimizări ale activelor
- Construiți optimizări
- Optimizări de livrare
- Rețea, HTTP/2, HTTP/3
- Testare și monitorizare
- Victorii rapide
- Totul pe o singură pagină
- Descărcați Lista de verificare (PDF, Apple Pages, MS Word)
- Abonați-vă la buletinul nostru informativ prin e-mail pentru a nu rata următoarele ghiduri.