Həftə 8 · 16/23
Event loop və yaddaş: donmayan, sızmayan kod
6 dəqiqəlik oxu
Mağazada bir kassir var. Kimsə otuz məhsulu bir-bir saydırırsa, arxadakı növbə dayanır — kassir «məşğuldur», amma heç kim irəliləmir. Bir də anbar: hər gün bir qutu gəlir, heç biri çıxarılmır.
JavaScript bir thread-də işləyir: uzun hesablama hər şeyi dondurur. Yaddaş isə unudulmuş istinadlarla dolur — bağlanmayan listener, həddi olmayan keş.
rows.sort(compare); // 200 000 rows, on the one thread: the page freezes
cache.set(id, value); // never deleted: the stockroom fills upÇox deyilən söz: JavaScript async-dir, deməli heç vaxt bloklanmır.
JavaScript bir thread-də işləyir. await yalnız gözləməni buraxır. Ağır sinxron iş (böyük sort, JSON, regex, döngü) bütün səhifəni və ya serveri dondurur. Yaddaş isə unudulmuş istinadlarla sızır: bağlanmayan listener, sərhədsiz keş, heç vaxt silinməyən timer. Seniorlar bunları hiss ilə yox, profiler ilə tapır və düzəlişi rəqəmlə sübut edir.
Sənin kulvarında
Long task interfeysi dondurur
Əsas thread-də 50ms-dən uzun iş kliki gecikdirir və bu, ölçülən bir göstəricidir (INP). Böyük siyahıları serverdə sırala, ya da Web Worker-ə ver.
Fikir eynidir, rəqəmlər və alətlər fərqli. Seçimin brauzerində yadda qalır və bütün dərslərə tətbiq olunur.
Uzun işi hissələrə böl
Hər hissədən sonra event loop-a növbə ver ki, kliklər və çəkmə arada keçsin. Daha ağır iş üçün Web Worker.
Sən bunu istə
for (let i = 0; i < rows.length; i += 1000) {
process(rows.slice(i, i + 1000));
await new Promise((r) => setTimeout(r, 0)); // let input through
}Hər keşə hədd qoy
Hədsiz keş uzun işləyən prosesdə yavaş sızmadır. Ölçü həddi (ən köhnəni at) və ya vaxt limiti (TTL) qoy.
Sən bunu istə
const cache = new Map();
function remember(key, value) {
cache.set(key, value);
if (cache.size > 500) cache.delete(cache.keys().next().value); // oldest first
}Sızmanı snapshot-ları müqayisə edərək tap
Snapshot al, eyni əməliyyatı on dəfə et, yenidən al. Hər dəfə artan və hələ də istinad olunan obyekt şübhəlidir.
Diff oxuyanda soruş: Profiler ilə ölç: 50ms-dən uzun iş varmı? Keşin həddi varmı? «Sürətləndirdim» deyən dəyişikliyin rəqəmi varmı?
Terminlər
İndi sən yoxla
1Klikdən sonra səhifə 2 saniyə donur. Hər şey async olduğu halda niyə?
button.onclick = async () => {
const rows = await fetch("/api/export").then((r) => r.json()); // 200k rows
rows.sort((a, b) => a.name.localeCompare(b.name));
render(rows);
};2Uzun işləyən serverdə bu keşin problemi nədir?
const cache = new Map();
export function getUser(id) {
if (!cache.has(id)) cache.set(id, fetchUser(id));
return cache.get(id);
}Hazır prompt
İngiliscədir, çünki terminlər ingiliscədir. Tərcümə etsən də terminləri saxla.
Profile <page or endpoint> before optimising anything.
- Record a performance trace of <interaction>; list every long task
(over 50 ms) with the function it comes from.
- Take a heap snapshot, repeat <action> ten times, take another;
list what grew and what still references it.
- For each finding, propose one fix (a Web Worker, chunking, memoizing,
removing a listener, bounding a cache) and the measurement that will
prove it worked.
Don't change code until I've seen the numbers.Öz kodunda
- 1DevTools Performance panelində ən ağır qarşılıqlı əlaqəni yaz və long task-ları tap.
- 2Memory panelində əməliyyatı 10 dəfə təkrarlamazdan əvvəl və sonra heap snapshot al, müqayisə et.
- 3Birini düzəlt, yenidən ölç və əvvəl/sonra rəqəmlərini commit mesajına yaz.
Bunu görəndə bitib: Bir long task və ya bir sızma üçün əvvəl/sonra rəqəmlərin var.
Daha dərinə
Oxumaq üçün