ЁЯУ▒ рдзрдбрд╛ 11 тАФ Web performance: рдкрд╛рд▓рдХрд╛рдВрдЪреНрдпрд╛ phone рд╡рд░рдЪреЗ рдирд┐рдХрд╛рд▓рд╛рдЪреЗ page
ЁЯУН рддреБрдореНрд╣реА рдЗрдереЗ рдЖрд╣рд╛рдд: 12 рдкреИрдХреА рдзрдбрд╛ 11 ┬╖ рдорд╛рдЧреЗ: lesson-10-database-queries ┬╖ рдкреБрдвреЗ: lesson-12-load-testing-budgets
ЁЯУж рдпрд╛ рдмреНрд░рдБрдЪрдордзреНрдпреЗ рдХрд╛рдп рдЖрд╣реЗ
рдзрдбреЗ 01тАУ10, рдЖрдгрд┐ performance рдЪрд╛ рддреЛ рднрд╛рдЧ рдЬреЛ user рд▓рд╛ рдкреНрд░рддреНрдпрдХреНрд╖ рджрд┐рд╕рддреЛ: browser рдордзрд▓реЗ page. Google рдЪреЗ
Core Web Vitals тАФ LCP (loading), INP (responsiveness) рдЖрдгрд┐ CLS (visual stability) тАФ
рдЖрдгрд┐ рд░реЛрдЬрдЪреЗ рдЙрдкрд╛рдп: рдХрдореА bytes, compression, scripts defer рдХрд░рдгреЗ, рд▓рд╣рд╛рди images, caching
headers, рдЖрдгрд┐ images рд╕рд╛рдареА рдЬрд╛рдЧрд╛ рд░рд╛рдЦреВрди рдареЗрд╡рдгреЗ. perf/demo.py рдордзреАрд▓ web() рдЖрдгрд┐
perf/sim.py рдордзреАрд▓ page_load, cls_score, inp_ms рдЖрдгрд┐ rate тАФ simulated page
load, рдПрдХ рд╢рд┐рдХрд╡рдгреНрдпрд╛рд╕рд╛рдареАрдЪреЗ model.
ЁЯзТ 5 рд╡рд░реНрд╖рд╛рдВрдЪреНрдпрд╛ рдореБрд▓рд╛рд▓рд╛ рд╕рдордЬрд╛рд╡рд▓реНрдпрд╛рд╕рд╛рд░рдЦреЗ
рдХрддрд░рд┐рдирд╛рдЪреА рдЖрдИ car park рдордзреНрдпреЗ, рдХрдордХреБрд╡рдд signal рдЕрд╕рддрд╛рдирд╛, рддрд┐рдЪреНрдпрд╛ phone рд╡рд░ рдХреНрд░реАрдбрд╛ рджрд┐рдирд╛рдЪреЗ рдирд┐рдХрд╛рд▓рд╛рдЪреЗ page рдЙрдШрдбрддреЗ. ЁЯУ▒
- Page рдЬрдб рдЖрд╣реЗ: рдПрдХ рдореЛрдард╛ script рдЖрдгрд┐ finish line рдЪрд╛ рдПрдХ рдкреНрд░рдЪрдВрдб рдлреЛрдЯреЛ. рдореЛрдард╛ рдлреЛрдЯреЛ рдЖрдгрд┐ рдирд┐рдХрд╛рд▓ рджрд┐рд╕рдгреНрдпрд╛рдЖрдзреА рддреА 5 рд╕реЗрдХрдВрдж рдерд╛рдВрдмрддреЗ. рддреА рдкреНрд░рддреАрдХреНрд╖рд╛ рдореНрд╣рдгрдЬреЗ LCP. ЁЯШ┤
- рддреА "рдорд╛рдЭреНрдпрд╛ рдореБрд▓реАрдЪреНрдпрд╛ рд╡реЗрд│рд╛ рджрд╛рдЦрд╡рд╛" рд╡рд░ tap рдХрд░рддреЗ. рд╕реЗрдХрдВрджрд╛рдЪреНрдпрд╛ рдПрдХ рддреГрддреАрдпрд╛рдВрд╢ рд╡реЗрд│ рдХрд╛рд╣реАрдЪ рд╣реЛрдд рдирд╛рд╣реА, рдХрд╛рд░рдг page рдПрдХ рд▓рд╛рдВрдм script рдЪрд╛рд▓рд╡рдгреНрдпрд╛рдд busy рдЖрд╣реЗ. рддреЛ рдЙрд╢реАрд░ рдореНрд╣рдгрдЬреЗ INP. ЁЯСЖтП│
- рддреА рд╡рд╛рдЪрд╛рдпрд▓рд╛ рд╕реБрд░реБрд╡рд╛рдд рдХрд░рддреЗ тАФ рдЖрдгрд┐ рдордЬрдХреВрд░ рдЦрд╛рд▓реА рдЙрдбреА рдорд╛рд░рддреЛ, рдХрд╛рд░рдг рдлреЛрдЯреЛ рд╢реЗрд╡рдЯреА load рдЭрд╛рд▓рд╛ рдЖрдгрд┐ рддреНрдпрд╛рдиреЗ рдордЬрдХреВрд░ рдврдХрд▓рд▓рд╛. рддреА рдХреБрдардкрд░реНрдпрдВрдд рд╡рд╛рдЪрд▓реЗ рддреЗ рд╡рд┐рд╕рд░рддреЗ. рддреА рдЙрдбреА рдореНрд╣рдгрдЬреЗ CLS. ЁЯШа
рдРрд╢реНрд╡рд░реНрдпрд╛ page рджреБрд░реБрд╕реНрдд рдХрд░рддреЗ: рддреА text files рджрд╛рдмреВрди рд▓рд╣рд╛рди рдХрд░рддреЗ (compression), рдореЛрдареНрдпрд╛ script рд▓рд╛ рдЖрдкрд▓реА рдкрд╛рд│реА рдпреЗрдИрдкрд░реНрдпрдВрдд рдерд╛рдВрдмрд╛рдпрд▓рд╛ рд╕рд╛рдВрдЧрддреЗ, рд▓рд╣рд╛рди рдлреЛрдЯреЛ рд╡рд╛рдкрд░рддреЗ, рдЖрдгрд┐ рдлреЛрдЯреЛрдЪреА рдЬрд╛рдЧрд╛ рд░рд╛рдЦреВрди рдареЗрд╡рддреЗ рдореНрд╣рдгрдЬреЗ рдХрд╛рд╣реАрдЪ рдЙрдбреА рдорд╛рд░рдд рдирд╛рд╣реА. рдЖрддрд╛ page рд╕реБрдорд╛рд░реЗ 1 рд╕реЗрдХрдВрджрд╛рдд рджрд┐рд╕рддреЗ. рдЖрдгрд┐ рджреБрд╕рд░реА рднреЗрдЯ рдЖрдгрдЦреА рд╡реЗрдЧрд╡рд╛рди рдЕрд╕рддреЗ, рдХрд╛рд░рдг phone рдиреЗ рдорд╛рдЧрдЪреНрдпрд╛ рд╡реЗрд│рдЪреНрдпрд╛ files рдЬрдкреВрди рдареЗрд╡рд▓реНрдпрд╛ рд╣реЛрддреНрдпрд╛.
ЁЯЧ║я╕П рдЖрдХреГрддреА
flowchart LR
a["as built ┬╖ 2210 KB<br/>LCP 5020 ms (poor)"] --> b["+ compress text<br/>LCP 3505 ms"]
b --> c["+ defer the script<br/>LCP 3055 ms"]
c --> d["+ smaller AVIF hero ┬╖ 452.5 KB<br/>LCP 1055 ms (good)"]
d --> e["repeat visit, cached<br/>LCP 450 ms"]
cls["CLS 0.1875 тЖТ 0.0<br/>set width/height"]
inp["INP 316 тЖТ 66 ms<br/>break up the long task"]
ЁЯЧ║я╕П рд░реЗрдЦрд╛рдЯрд▓реЗрд▓реА рдЖрд╡реГрддреНрддреА + рдПрдХ lab: https://school-edh.pages.dev/performance/lesson-diagrams.html#l11
тЭУ рдХрд╛рдп
- Core Web Vitals тАФ user-рдХреЗрдВрджреНрд░рд┐рдд рддреАрди metrics рдЬреНрдпрд╛рдВрдЪреНрдпрд╛ рдорд░реНрдпрд╛рджрд╛ Google рдкреНрд░рдХрд╛рд╢рд┐рдд рдХрд░рддреЗ, рдЦрд▒реНрдпрд╛ page
рднреЗрдЯреАрдВрдЪреНрдпрд╛ (field data) 75th percentile рд╡рд░, phones рдЖрдгрд┐ desktops рд╕рд╛рдареА рд╡реЗрдЧрд╡реЗрдЧрд│реЗ рдореЛрдЬрд▓реЗрд▓реЗ:
- LCP (Largest Contentful Paint) тАФ рджреГрд╢реНрдп рднрд╛рдЧрд╛рддреАрд▓ рд╕рд░реНрд╡рд╛рдд рдореЛрдареА image рдХрд┐рдВрд╡рд╛ text block рдХреЗрд╡реНрд╣рд╛ paint рд╣реЛрддреЛ. Good тЙд 2.5 s, poor > 4 s.
- INP (Interaction to Next Paint) тАФ tap, click рдХрд┐рдВрд╡рд╛ key press рдирдВрддрд░ рдХрд┐рддреА рд╡реЗрд│рд╛рдиреЗ page рддреНрдпрд╛рдЪреЗ рдЙрддреНрддрд░
paint рдХрд░рддреЗ: input delay + event handling + presentation. Good тЙд 200 ms, poor
500 ms. March 2024 рдордзреНрдпреЗ INP рдиреЗ Core Web Vital рдореНрд╣рдгреВрди FID рдЪреА рдЬрд╛рдЧрд╛ рдШреЗрддрд▓реА (First Input Delay); FID рдлрдХреНрдд рдкрд╣рд┐рд▓реНрдпрд╛ interaction рдЪрд╛ handler рд╕реБрд░реВ рд╣реЛрдгреНрдпрд╛рдЖрдзреАрдЪрд╛ рдЙрд╢реАрд░ рдореЛрдЬрдд рдЕрд╕реЗ.
- CLS (Cumulative Layout Shift) тАФ рджрд┐рд╕рдгрд╛рд░рд╛ content рдЕрдирдкреЗрдХреНрд╖рд┐рддрдкрдгреЗ рдХрд┐рддреА рдЙрдбреА рдорд╛рд░рддреЛ. рдПрдХрд╛ shift рдЪрд╛ score impact fraction ├Ч distance fraction рдЕрд╕рддреЛ; CLS рдореНрд╣рдгрдЬреЗ рдЕрд╢рд╛ scores рдЪрд╛ рд╕рд░реНрд╡рд╛рдд рдореЛрдард╛ рдЧрдЯ ("session window"). Good тЙд 0.1, poor > 0.25.
- Lab рд╡рд┐рд░реБрджреНрдз field data тАФ Lighthouse рдЖрдгрд┐ DevTools рдПрдХрд╛ simulated device рд╡рд░ рдПрдХ load рдореЛрдЬрддрд╛рдд (lab);
Chrome UX Report рдЖрдгрд┐
web-vitalslibrary рдЦрд░реЗ users рдореЛрдЬрддрд╛рдд (field). рдЦрд▒реНрдпрд╛ interactions рд╢рд┐рд╡рд╛рдп lab tools INP рдореЛрдЬреВ рд╢рдХрдд рдирд╛рд╣реАрдд; рддреНрдпрд╛рдРрд╡рдЬреА Lighthouse Total Blocking Time рджрд╛рдЦрд╡рддреЛ. - Render-blocking resources тАФ CSS, рдЖрдгрд┐
defer/asyncрд╢рд┐рд╡рд╛рдп<head>рдордзреАрд▓ scripts, download (рдЖрдгрд┐ run) рд╣реЛрдИрдкрд░реНрдпрдВрдд рдкрд╣рд┐рд▓рд╛ paint рдерд╛рдВрдмрд╡рддрд╛рдд. - Compression тАФ text (HTML, CSS, JS, JSON) gzip рдХрд┐рдВрд╡рд╛ Brotli рдиреЗ (рдЖрдгрд┐ рдирд╡реНрдпрд╛ browsers рдордзреНрдпреЗ
zstd рдиреЗ) рдЦреВрдк рдЫрд╛рди compress рд╣реЛрддреЛ. Browser рдЪреНрдпрд╛
Accept-Encodingheader рдордзреВрди server рдПрдХ рдирд┐рд╡рдбрддреЛ. Images рдЖрдгрд┐ video рдЖрдзреАрдЪ compressed рдЕрд╕рддрд╛рдд; рддреНрдпрд╛рдРрд╡рдЬреА modern formats (AVIF, WebP) рдЖрдгрд┐ рдпреЛрдЧреНрдп рдЖрдХрд╛рд░ рд╡рд╛рдкрд░рд╛. - Caching headers тАФ рдЬреНрдпрд╛ files рдЪреНрдпрд╛ рдирд╛рд╡рд╛рдд content hash рдЖрд╣реЗ (
app.3f9a1c.js) рддреНрдпрд╛рдВрдЪреНрдпрд╛рд╕рд╛рдареАCache-Control: max-age=31536000, immutable: browser рди рд╡рд┐рдЪрд╛рд░рддрд╛ рд╡рд░реНрд╖рднрд░ рддреНрдпрд╛ рдкреБрдиреНрд╣рд╛ рд╡рд╛рдкрд░рддреЛ. HTML рд╕рд╛рдареАCache-Control: no-cache: browser рддреЗ рдареЗрд╡реВ рд╢рдХрддреЛ рдкрдг рддреНрдпрд╛рд▓рд╛ revalidate рдХрд░рд╛рд╡реЗ рд▓рд╛рдЧрддреЗ (ETagрд╕рд╣If-None-Match), рдЖрдгрд┐ рдХрд╛рд╣реАрдЪ рдмрджрд▓рд▓реЗ рдирд╕реЗрд▓ рддрд░ рддреНрдпрд╛рд▓рд╛ рдЫреЛрдЯрд╛рд╕рд╛ 304 Not Modified рдорд┐рд│рддреЛ. (no-storeрдЪрд╛ рдЕрд░реНрде "рдареЗрд╡реВ рдирдХрд╛" рдЕрд╕рд╛ рдЖрд╣реЗ.)
ЁЯдФ рдХрд╛
рдХрд╛рд░рдг user рдЪрд╛ рд╡реЗрд│ page рд╡рд░рдЪ рдЬрд╛рддреЛ. 2 MB рдЪреНрдпрд╛ page рдорд╛рдЧрдЪреЗ рд╡реЗрдЧрд╡рд╛рди API рдореНрд╣рдгрдЬреЗ рд╣рд│реВ product. рдХрдордХреБрд╡рдд signal рдЕрд╕рд▓реЗрд▓реНрдпрд╛ phone рд╡рд░ рдкреНрд░рддреНрдпреЗрдХ round trip рдЖрдгрд┐ рдкреНрд░рддреНрдпреЗрдХ kilobyte рдорд╣рд╛рдЧ рдЕрд╕рддреЛ (рдкреБрдиреНрд╣рд╛ рдзрдбрд╛ 07 рдЪрд╛ toll), рдЖрдгрд┐ рд▓рд╛рдВрдм script рдореБрд│реЗ рдкреНрд░рддреНрдпреЗрдХ tap рдмрд┐рдШрдбрд▓реНрдпрд╛рд╕рд╛рд░рдЦрд╛ рд╡рд╛рдЯрддреЛ. Search engines рд╕реБрджреНрдзрд╛ ranking рдЪреНрдпрд╛ рдПрдХрд╛ signal рдореНрд╣рдгреВрди рд╣реЗ metrics рд╡рд╛рдкрд░рддрд╛рдд.
ЁЯФз рдХрд╕реЗ (рдпрд╛ repo рдордзреНрдпреЗ)
perf/sim.py рдордзреАрд▓ page_load(...) рд╣реЗ рд╣рд│реВ phone network рд╡рд░рдЪреНрдпрд╛ рдПрдХрд╛ load рдЪреЗ
model рдЖрд╣реЗ: connect рдХрд░рд╛рдпрд▓рд╛ 2 round trips (TCP + TLS 1.3) рд▓рд╛рдЧрддрд╛рдд, HTML рд▓рд╛ 1 round trip рдЕрдзрд┐рдХ рддреНрдпрд╛рдЪреЗ
bytes, рдордЧ рдкрд╣рд┐рд▓реНрдпрд╛ рдореЛрдареНрдпрд╛ paint рд╕рд╛рдареА рд▓рд╛рдЧрдгрд╛рд░реЗ рд╕рдЧрд│реЗ (CSS, hero image, рдЖрдгрд┐ defer рдХреЗрд▓реЗрд▓рд╛ рдирд╕реЗрд▓ рддрд░ script)
bandwidth рд╡рд╛рдЯреВрди parallel download рд╣реЛрддреЗ. рддреЗ рд╕рдВрдкрддреЗ рддреЗрд╡реНрд╣рд╛ LCP. compress=True text 25% рдкрд░реНрдпрдВрдд рд▓рд╣рд╛рди рдХрд░рддреЗ
(рдПрдХ рдиреЗрд╣рдореАрдЪреЗ рдкреНрд░рдорд╛рдг тАФ рдПрдХ рдЧреГрд╣реАрддрдХ). рдЦрд▒реНрдпрд╛ browsers рдордзреНрдпреЗ priorities, HTTP/2 рдЖрдгрд┐ HTTP/3 multiplexing
рдЖрдгрд┐ TCP slow start рдЕрд╕рддрд╛рдд, рдЬреЗ model рд╕реЛрдбреВрди рджреЗрддреЗ. cls_score, inp_ms рдЖрдгрд┐ rate рд╡рд░реАрд▓ рд╡реНрдпрд╛рдЦреНрдпрд╛ рдЖрдгрд┐
рдорд░реНрдпрд╛рджрд╛ рд▓рд╛рдЧреВ рдХрд░рддрд╛рдд.
ЁЯзк рдХрд░реВрди рдкрд╛рд╣рд╛
python3 perf/demo.py web
python3 - <<'EOF'
import sys; sys.path.insert(0, "perf"); from sim import page_load, rate
for rtt, bw in ((50, 2000), (150, 500), (300, 150)):
for label, kw in (("as built", {}), ("all fixes", dict(compress=True, defer_js=True, hero_kb=200))):
lcp, kb = page_load(rtt_ms=rtt, kb_per_s=bw, **kw)
print(f"RTT {rtt:>3} ms, {bw:>4} KB/s, {label:<9} тЖТ LCP {lcp:>5} ms ({rate('LCP', lcp)})")
EOF
тЬЕ рддрдкрд╛рд╕рд╛ тАФ рддреБрдореНрд╣рд╛рд▓рд╛ рдХрд╛рдп рджрд┐рд╕рд╛рдпрд▓рд╛ рд╣рд╡реЗ
web рд╣реЗ рдЫрд╛рдкрддреЗ:
тФАтФА the sports-day results page on a phone: 150 ms round trip, 500 KB/s (a teaching model of one page load)
as built: 30 KB HTML, 80 KB CSS, 900 KB JS, 1200 KB hero image LCP 5020 ms (poor) ┬╖ 2210 KB
+ compress text (gzip/Brotli, text to about 25%) LCP 3505 ms (needs improvement) ┬╖ 1452.5 KB
+ defer the script (no longer blocks the first paint) LCP 3055 ms (needs improvement) ┬╖ 1452.5 KB
+ resize the hero and serve AVIF (1200 тЖТ 200 KB) LCP 1055 ms (good) ┬╖ 452.5 KB
repeat visit: files cached, the HTML revalidated (304) LCP 450 ms (good) ┬╖ 0 KB
(hashed files: Cache-Control: max-age=31536000, immutable ┬╖ the HTML: Cache-Control: no-cache)
тФАтФА CLS: an image with no width/height pushes the text down a quarter of the screen тЖТ 0.1875 (needs improvement) ┬╖ with width/height set тЖТ 0.0 (good)
тФАтФА INP: a tap runs 300 ms of script in one piece тЖТ 316 ms (needs improvement) ┬╖ in 50 ms chunks that yield тЖТ 66 ms (good)
рддреБрдордЪрд╛ snippet рд╣реЗ рдЫрд╛рдкрддреЛ:
RTT 50 ms, 2000 KB/s, as built тЖТ LCP 1305 ms (good)
RTT 50 ms, 2000 KB/s, all fixes тЖТ LCP 314 ms (good)
RTT 150 ms, 500 KB/s, as built тЖТ LCP 5020 ms (poor)
RTT 150 ms, 500 KB/s, all fixes тЖТ LCP 1055 ms (good)
RTT 300 ms, 150 KB/s, as built тЖТ LCP 15933 ms (poor)
RTT 300 ms, 150 KB/s, all fixes тЖТ LCP 2717 ms (needs improvement)
ЁЯПБ рддреБрдореНрд╣реА рдЖрддреНрддрд╛рдЪ рдХрд╛рдп рд╕рд┐рджреНрдз рдХреЗрд▓реЗ
Developer рдЪреНрдпрд╛ рд╡реЗрдЧрд╡рд╛рди connection рд╡рд░ good (1305 ms) рджрд┐рд╕рдгрд╛рд░реЗ page рдкрд╛рд▓рдХрд╛рдВрдЪреНрдпрд╛ phone рд╡рд░ poor (5020 ms) рдЖрд╣реЗ, рдЖрдгрд┐ рдЦреВрдк рд╣рд│реВ connection рд╡рд░ рдЬрд╡рд│рдЬрд╡рд│ 16 рд╕реЗрдХрдВрдж тАФ рддреБрдордЪреНрдпрд╛ users рдХрдбреЗ рдЕрд╕рд▓реЗрд▓реНрдпрд╛ network рд╡рд░ test рдХрд░рд╛. рд╕рдорд╕реНрдпреЗрдЪрд╛ рдмрд╣реБрддреЗрдХ рднрд╛рдЧ bytes рд╣реЛрддреЗ: compression, defer рдХрд░рдгреЗ рдЖрдгрд┐ рдпреЛрдЧреНрдп рдЖрдХрд╛рд░рд╛рдЪреА image рдпрд╛рдВрдиреА LCP 5020 рд╡рд░реВрди 1055 ms рд╡рд░ рдЖрдгрд▓рд╛, рдЖрдгрд┐ caching рдиреЗ рдкреБрдиреНрд╣рд╛ рднреЗрдЯ 450 ms рд╡рд░ рдЖрдгрд▓реА тАФ рдлрдХреНрдд рддреАрди round trips, bytes рд╢реВрдиреНрдп. CLS shift 0.75 ├Ч 0.25 = 0.1875 рд╣реЛрддрд╛; image рдЪреА рдЬрд╛рдЧрд╛ рд░рд╛рдЦреВрди рдареЗрд╡рд▓реНрдпрд╛рдиреЗ рддреЛ 0 рдЭрд╛рд▓рд╛. 300 ms рдЪреНрдпрд╛ task рдЪреЗ 50 ms рдЪреЗ рддреБрдХрдбреЗ рдХреЗрд▓реНрдпрд╛рдиреЗ page рдиреЗ tap рд▓рд╛ 66 ms рдордзреНрдпреЗ рдЙрддреНрддрд░ рджрд┐рд▓реЗ тАФ рдПрдХреВрдг рдХрд╛рдо рддреЗрд╡рдвреЗрдЪ, рдкрдг page рдордзреЗрдордзреЗ paint рдХрд░реВ рд╢рдХрддреЗ.
тЪая╕П рдиреЗрд╣рдореАрдЪреНрдпрд╛ рдЪреБрдХрд╛
- office Wi-Fi рд╡рд░рдЪреНрдпрд╛ рд╡реЗрдЧрд╡рд╛рди laptop рд╡рд░рдЪ test рдХрд░рдгреЗ
- hero image рд╡рд░
loading="lazy"тАФ рддреЛрдЪ LCP element рдЖрд╣реЗ; рддреЛ рд▓рд╡рдХрд░ load рдХрд░рд╛ (fetchpriority="high") widthрдЖрдгрд┐height(рдХрд┐рдВрд╡рд╛ CSSaspect-ratio) рдирд╕рд▓реЗрд▓реНрдпрд╛ images, content рдЪреНрдпрд╛ рд╡рд░ рдШреБрд╕рд╡рд▓реЗрд▓реНрдпрд╛ ads рдЖрдгрд┐ banners тАФ layout shifts- page paint рд╣реЛрдгреНрдпрд╛рдЖрдзреА рд╕рдЧрд│реЗ рдХрд╛рд╣реА рдХрд░рдгрд╛рд░рд╛ рдПрдХрдЪ рд▓рд╛рдВрдм event handler
Cache-Control: no-cacheрдЪрд╛ рдЕрд░реНрде "cache рдХрд░реВ рдирдХрд╛" рдЕрд╕рд╛ рдШреЗрдгреЗ тАФ рддреНрдпрд╛рдЪрд╛ рдЕрд░реНрде "рдЖрдзреА revalidate рдХрд░рд╛"- рдирд╛рд╡рд╛рдд hash рдирд╕рд▓реЗрд▓реНрдпрд╛ files рд╡рд░ рд▓рд╛рдВрдм cache times тАФ users рдХрдбреЗ рдЬреБрдиреНрдпрд╛ versions рд░рд╛рд╣рддрд╛рдд
ЁЯПн рдкреНрд░рддреНрдпрдХреНрд╖ рд╡рд╛рдкрд░рд╛рдд
рдЦрд▒реНрдпрд╛ account рд╡рд░ тАФ compression рдЖрдгрд┐ caching headers рддрдкрд╛рд╕рд╛:
curl -sI -H 'Accept-Encoding: br, gzip' https://results.school.example/app.3f9a1c.js | grep -iE 'content-encoding|cache-control|etag'
npx lighthouse https://results.school.example/ --only-categories=performance --form-factor=mobile
рдЙрдкрд╛рдп рд▓рд╛рдЧреВ рдХреЗрд▓реЗрд▓реЗ HTML:
<link rel="stylesheet" href="/style.8c1d2e.css">
<script src="/app.3f9a1c.js" defer></script>
<img src="/hero-800.avif" width="800" height="450" fetchpriority="high" alt="Runners crossing the finish line">
NGINX: text рд╕рд╛рдареА gzip, hashed assets рд╕рд╛рдареА рд▓рд╛рдВрдм caching (Brotli рд▓рд╛ ngx_brotli module рд▓рд╛рдЧрддреЛ):
gzip on;
gzip_types text/css application/javascript application/json image/svg+xml;
location ~* \.[0-9a-f]{6,}\.(js|css|avif|woff2)$ { add_header Cache-Control "public, max-age=31536000, immutable"; }
location = /index.html { add_header Cache-Control "no-cache"; }
web-vitals library рдиреЗ рдЦрд░реЗ users рдореЛрдЬрд╛, рдЖрдгрд┐ рд▓рд╛рдВрдм tasks рдЪреЗ рддреБрдХрдбреЗ рдХрд░рд╛:
import { onLCP, onINP, onCLS } from 'web-vitals';
[onLCP, onINP, onCLS].forEach(on => on(m => navigator.sendBeacon('/vitals', JSON.stringify(m))));
async function showTimes(rows) {
for (const chunk of chunks(rows, 200)) {
render(chunk);
await (globalThis.scheduler?.yield?.() ?? new Promise(r => setTimeout(r, 0))); // let the browser paint
}
}
ЁЯПн рдкреНрд░рддреНрдпрдХреНрд╖ рд╡рд╛рдкрд░рд╛рдд рд╣реЗ рдХрд╛ рдорд╣рддреНрддреНрд╡рд╛рдЪреЗ: phones рд╕рд╛рдареА p75 рд╡рд░рдЪрд╛ field data рдкрд╛рд╣рдд рд░рд╛рд╣рд╛, рдкреНрд░рддреНрдпреЗрдХ page рд▓рд╛ byte budget рджреНрдпрд╛, рдЖрдгрд┐ рдкреНрд░рддреНрдпреЗрдХ рдирд╡реНрдпрд╛ third-party script рд▓рд╛ рдХрд╛рд░рдг рд▓рд╛рдЧрдгрд╛рд░рд╛ performance рдмрджрд▓ рд╕рдордЬрд╛.
тПня╕П рдкреБрдвреЗ
рдкреНрд░рддреНрдпреЗрдХ рдзрдбреНрдпрд╛рдиреЗ рдХрд╛рд╣реАрддрд░реА рд╡реЗрдЧрд╡рд╛рди рдХреЗрд▓реЗ. рд╢реЗрд╡рдЯрдЪрд╛ рдзрдбрд╛ рддреЗ рд╡реЗрдЧрд╡рд╛рди рд░рд╛рд╣реАрд▓ рдпрд╛рдЪреА рдЦрд╛рддреНрд░реА рдХрд░рддреЛ: load tests, CI рдордзрд▓реЗ performance budgets, рдЖрдгрд┐ рд╕рдВрдкреВрд░реНрдг рдЪрд┐рддреНрд░.
git checkout lesson-12-load-testing-budgets