# JavaScript tezlik va optimallashtirish

> Kodni tezlashtirish: o'lchash usullari, DOM bilan tez ishlash, reflow, sikl optimallashtirish, xotira oqishi va yuklash tezligi. Amaliy o'lchovlar bilan.

Manba: https://learncode.uz/javascript/optimallashtirish/
Sana: 2026-06-09

Sekin sahifadan foydalanuvchi ketadi. Bu darsda tezlikka eng ko'p ta'sir
qiladigan joylar va ularni qanday o'lchash kerakligi.

## Avval o'lchang

> **Asosiy qoida**
>
> **Taxmin qilib optimallashtirmang.** Kod qayerda sekinlashayotgani deyarli
> har doim kutilganidan boshqa joyda bo'ladi. Avval o'lchang, keyin tuzating,
> so'ng yana o'lchang.
>
> Erta optimallashtirish kodni murakkablashtiradi va odatda hech narsa
> tejamaydi.

```js
function measure(title, action) {
  const startTime = performance.now();
  const result = action();
  const elapsed = performance.now() - startTime;
  console.log(title + ": " + elapsed.toFixed(2) + " ms");
  return result;
}

const arr = Array.from({ length: 200000 }, (_, i) => i);

measure("for sikli", () => {
  let s = 0;
  for (let i = 0; i < arr.length; i++) s += arr[i];
  return s;
});

measure("for...of", () => {
  let s = 0;
  for (const n of arr) s += n;
  return s;
});

measure("reduce", () => arr.reduce((a, b) => a + b, 0));
```

`performance.now()` — `Date.now()` dan aniqroq (kasr millisekund).

## Qidiruv: massiv va Set

```js
const n = 50000;
const arr = Array.from({ length: n }, (_, i) => i);
const numberSet = new Set(arr);

const start1 = performance.now();
let foundInArray = 0;
for (let i = 0; i < 2000; i++) {
  if (arr.includes(n - 1)) foundInArray++;
}
console.log("includes:", (performance.now() - start1).toFixed(1), "ms");

const start2 = performance.now();
let foundInSet = 0;
for (let i = 0; i < 2000; i++) {
  if (numberSet.has(n - 1)) foundInSet++;
}
console.log("Set.has:", (performance.now() - start2).toFixed(1), "ms");
```

Farq juda katta. Ko'p marta qidiriladigan ma'lumot uchun
[Set yoki Map](https://learncode.uz/javascript/set-map) tanlang — bu eng ko'p foyda beradigan
o'zgarishlardan biri.

## Ichma-ich sikldan qutulish

```js
const students = Array.from({ length: 1000 }, (_, i) => ({
  id: i, name: "Talaba " + i,
}));
const scores = Array.from({ length: 1000 }, (_, i) => ({
  studentId: i, score: 60 + (i % 40),
}));

// Sekin: har talaba uchun butun ballar massivi qidiriladi
const start1 = performance.now();
const result1 = students.map((s) => ({
  ...s,
  score: scores.find((x) => x.studentId === s.id)?.score,
}));
console.log("find bilan:", (performance.now() - start1).toFixed(1), "ms");

// Tez: avval Map yasaladi, keyin bir marta yuriladi
const start2 = performance.now();
const scoreById = new Map(scores.map((s) => [s.studentId, s.score]));
const result2 = students.map((s) => ({ ...s, score: scoreById.get(s.id) }));
console.log("Map bilan:", (performance.now() - start2).toFixed(1), "ms");

console.log("Natija bir xil:", result1[500].score === result2[500].score);
```

Birinchi variant har element uchun qidiruv qiladi — ish hajmi kvadratik
o'sadi. Ikkinchisida ma'lumot bir marta indekslanadi.

## DOM — eng qimmat qism

> **Atama**
>
> **Reflow** (qayta joylashtirish) — brauzer elementlar o'lchami va o'rnini
> qaytadan hisoblashi. **Repaint** — qayta chizish. Reflow qimmatroq va uni
> `offsetHeight`, `getBoundingClientRect` kabi o'lchov xossalari majburlaydi.

```js
const n = 2000;

const a = document.querySelector("#a");
const start1 = performance.now();
for (let i = 0; i < n; i++) {
  const div = document.createElement("div");
  div.textContent = "Qator " + i;
  a.append(div);
}
console.log("Bittalab append:", (performance.now() - start1).toFixed(1), "ms");

const b = document.querySelector("#b");
const start2 = performance.now();
const fragment = document.createDocumentFragment();
for (let i = 0; i < n; i++) {
  const div = document.createElement("div");
  div.textContent = "Qator " + i;
  fragment.append(div);
}
b.append(fragment);
console.log("Fragment bilan:", (performance.now() - start2).toFixed(1), "ms");
```

```html
<div id="a"></div><div id="b"></div>
```

[DocumentFragment](https://learncode.uz/javascript/dom-yaratish) sahifaga bir marta tegadi,
bittalab `append` esa har safar.

> **Farq har doim ham katta emas**
>
> Zamonaviy brauzerlar o'zgarishlarni o'zi guruhlaydi, shuning uchun bu
> misolda ikki usul yaqin natija berishi mumkin — ba'zan fragment hatto
> sekinroq chiqadi.
>
> Farq **o'lchov xossasi** (`offsetHeight`, `getBoundingClientRect`) qo'shilganda
> keskin ortadi: u brauzerni har safar darhol qayta hisoblashga majbur qiladi.
> Shuning uchun quyidagi bo'lim — bu darsdagi eng muhim qoida.

## O'qish va yozishni aralashtirmang

```js
// ❌ Yomon: har aylanishda majburiy reflow
for (const el of elements) {
  el.style.height = el.offsetHeight + 10 + "px";
}

// ✅ Yaxshi: avval hammasini o'qish, keyin yozish
const heights = elements.map((el) => el.offsetHeight);
elements.forEach((el, i) => {
  el.style.height = heights[i] + 10 + "px";
});
```

O'qish va yozish navbatlashsa, brauzer har safar qaytadan hisoblashga majbur
bo'ladi — bu **layout thrashing** deb ataladi.

## Hodisalarni cheklash

Tez-tez ishlaydigan hodisalar (`scroll`, `resize`, `input`) uchun
[debounce va throttle](https://learncode.uz/javascript/timerlar) majburiy:

```js
window.addEventListener("scroll", throttle(() => {
  console.log(window.scrollY);
}, 100));
```

Aks holda funksiya soniyasiga o'nlab marta chaqiriladi.

## Xotira oqishi

```js
// Tinglovchi olib tashlanmasa, el xotirada qoladi
function bad(el) {
  const bigData = new Array(100000).fill("x");
  el.addEventListener("click", () => {
    console.log(bigData.length);
  });
}

// To'g'ri: kerak bo'lmaganda olib tashlash
function good(el) {
  const action = () => console.log("onClick");
  el.addEventListener("click", action);
  return () => el.removeEventListener("click", action);
}

console.log("Tozalash funksiyasini qaytarish — standart pattern");

// Yoki avtomatik: bir marta ishlaydigan tinglovchi
console.log("Muqobil: { once: true } yoki AbortController");
```

Uch keng tarqalgan sabab: olib tashlanmagan tinglovchilar, to'xtatilmagan
`setInterval` va o'sib boruvchi global massiv/kesh.

## Yuklash tezligi

Ko'pincha JavaScript'ning **hajmi** uning tezligidan muhimroq:

| Usul | Ta'siri |
|---|---|
| Dinamik `import()` | Kerak bo'lmagan kod yuklanmaydi |
| Tree shaking | Ishlatilmagan eksportlar tushmaydi |
| Kutubxonani tanlash | Katta paket o'rniga kichigi yoki o'z kodingiz |
| `defer` / `type="module"` | HTML tahlilini to'smaydi |
| Rasm formati va o'lchami | Odatda JS'dan ko'proq bayt |

> **Nimadan boshlash kerak**
>
> Amalda tezlikni eng ko'p oshiradigan uchta narsa:
>
> 1. **Rasmlar** — to'g'ri o'lcham va WebP formati;
> 2. **JavaScript hajmi** — kerak bo'lmagan kutubxonani olib tashlash;
> 3. **Qidiruv tuzilmasi** — massiv o'rniga `Map`/`Set`.
>
> Sikl ichidagi mayda tuzatishlar odatda sezilmaydi.

## O'lchash vositalari

- **DevTools → Performance** — yozib olish, qaysi funksiya qancha
  vaqt olganini ko'rish;
- **Lighthouse** — sahifa bahosi va tavsiyalar;
- **Network** — nima yuklanmoqda va qancha vaqtda;
- `performance.now()` — kod ichida aniq o'lchov.

[DevTools](https://learncode.uz/javascript/devtools) darsida asosiy panellar ko'rilgan.

## Amaliy mashq

1. `performance.now()` bilan uch xil sikl usulini solishtiring;
2. `includes` va `Set.has` ni katta massivda o'lchang;
3. ichma-ich `find` ni `Map` bilan almashtiring;
4. 2000 element qo'shishni fragment bilan va fragmentsiz o'lchang;
5. `scroll` hodisasiga throttle qo'shing;
6. DevTools Performance panelida yozib olib ko'ring.

## Qisqacha xulosa

- **Avval o'lchang** — taxmin bilan optimallashtirmang.
- Ko'p qidiriladigan ma'lumot uchun `Set`/`Map` — eng katta foyda.
- Ichma-ich sikl o'rniga oldindan indeks yasang.
- DOM'ga bir marta teging: `DocumentFragment`, guruhlangan o'zgartirish.
- O'qish va yozishni aralashtirmang (layout thrashing).
- Tinglovchi va `setInterval` ni tozalang — xotira oqishi.
- Ko'pincha kod hajmi tezligidan muhimroq.

Keyingi darsda [xavfsizlik asoslari](https://learncode.uz/javascript/xavfsizlik).
