Performance pattern'lar
Angular ilovasida performance — change detection strategiyasi, DOM qayta yaratilmasligi, pure pipe, virtual scroll va bundle optimizatsiyasi orqali erishiladi. Bu guruh intervyuda eng ko'p so'raladigan amaliy pattern'larni qamrab oladi.
OnPush + async pipe — eng tez pattern
Nima bu?
ChangeDetectionStrategy.OnPush komponentni faqat yangi @Input reference, ichki event, async pipe yangi qiymati yoki markForCheck() da tekshiradi. async pipe Observable'ni subscribe qiladi va yangi qiymat kelganda avtomatik CD trigger qiladi — manual subscribe va ChangeDetectorRef.detectChanges() kerak emas. Immutable data + OnPush — eng samarali kombinatsiya.
Kod misoli
import { Component, ChangeDetectionStrategy, inject } from '@angular/core';
import { AsyncPipe } from '@angular/common';
import { Observable, map } from 'rxjs';
import { UserService } from './user.service';
interface User {
id: number;
name: string;
active: boolean;
}
@Component({
selector: 'app-user-list',
standalone: true,
imports: [AsyncPipe],
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
@if (users$ | async; as users) {
<ul>
@for (user of users; track user.id) {
<li>{{ user.name }}</li>
}
</ul>
}
`,
})
export class UserListComponent {
private userService = inject(UserService);
users$: Observable<User[]> = this.userService.getUsers().pipe(
map((users) => users.filter((u) => u.active))
);
}
// XATO — OnPush + manual mutate (CD ishlamaydi)
this.users.push(newUser); // ❌
// TO'G'RI — yangi reference
this.users = [...this.users, newUser]; // ✅
// yoki signal/update pattern
Imtihonda
- OnPush qachon CD trigger bo'ladi?
asyncpipe unsubscribe qiladi mi?- OnPush bilan
BehaviorSubjectqanday ishlatiladi?
Yodlash uchun
OnPush + immutable data + async pipe = minimal CD.
trackBy — *ngFor DOM qayta yaratilmasin
Nima bu?
Ro'yxat yangilanganda Angular default holda index bo'yicha solishtiradi — element qo'shilsa yoki o'chirilsa ko'p DOM node qayta yaratiladi. trackBy (klassik) yoki track (Angular 17+) unique id bo'yicha mavjud node'larni qayta ishlatadi. Input focus, animation va performance saqlanadi.
Kod misoli
import { Component, signal } from '@angular/core';
import { NgFor } from '@angular/common';
interface Item {
id: number;
label: string;
}
@Component({
selector: 'app-track-demo',
standalone: true,
template: `
<!-- Angular 17+ — track majburiy -->
@for (item of items(); track item.id) {
<input [value]="item.label" />
}
<!-- Klassik *ngFor + trackBy -->
<div *ngFor="let item of items(); trackBy: trackById">
{{ item.label }}
</div>
`,
imports: [NgFor],
})
export class TrackDemoComponent {
items = signal<Item[]>([
{ id: 1, label: 'Birinchi' },
{ id: 2, label: 'Ikkinchi' },
]);
trackById(_index: number, item: Item): number {
return item.id;
}
prepend(): void {
this.items.update((list) => [
{ id: Date.now(), label: 'Yangi' },
...list,
]);
}
}
Imtihonda
trackBybo'lmasa nima muammo bo'ladi?track $indexqachon xavfli?@for ... trackva*ngFor trackByfarqi?
Yodlash uchun
Unique id bilan track — DOM reuse; $index faqat statik ro'yxat.
Pure pipe — computed qiymatlar
Nima bu?
Pure pipe (default) — faqat primitive @Input yoki ob'ekt reference o'zgarganda qayta hisoblanadi. Template'da method chaqirish ({{ getTotal() }}) har CD da ishlaydi; pure pipe esa cache qiladi. impure: true har CD da ishlaydi — faqat zarurat bo'lsa. Currency, Date, Async pipe — built-in pure.
Kod misoli
import { Pipe, PipeTransform } from '@angular/core';
import { CurrencyPipe } from '@angular/common';
interface OrderLine {
product: string;
qty: number;
price: number;
}
@Pipe({ name: 'orderTotal', standalone: true })
export class OrderTotalPipe implements PipeTransform {
transform(lines: OrderLine[], taxRate = 0.12): number {
const subtotal = lines.reduce((sum, l) => sum + l.qty * l.price, 0);
return subtotal * (1 + taxRate);
}
}
@Component({
selector: 'app-order-summary',
standalone: true,
imports: [OrderTotalPipe, CurrencyPipe],
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<!-- Pure pipe — lines reference o'zgarganda hisoblanadi -->
<p>Jami: {{ lines | orderTotal:0.12 | currency:'UZS' }}</p>
<!-- ❌ Har CD da chaqiriladi -->
<!-- <p>{{ calculateTotal() }}</p> -->
`,
})
export class OrderSummaryComponent {
lines: OrderLine[] = [
{ product: 'Kitob', qty: 2, price: 50_000 },
{ product: 'Daftar', qty: 1, price: 15_000 },
];
}
Imtihonda
- Pure va impure pipe farqi?
- Pipe vs getter vs computed signal qachon tanlanadi?
- Pure pipe ob'ekt ichidagi property o'zgarsa nima bo'ladi?
Yodlash uchun
Pure pipe = reference o'zgarganda; method call = har CD.
Virtual Scrolling — CDK (katta ro'yxat)
Nima bu?
Virtual scrolling — faqat viewport'da ko'rinadigan elementlar DOM'da render qilinadi (odatda + buffer). 10 000+ qatorli ro'yxatlar uchun @angular/cdk/scrolling cdk-virtual-scroll-viewport ishlatiladi. itemSize (fixed) yoki AutosizeVirtualScrollStrategy (dynamic height) tanlanadi.
Kod misoli
import { Component } from '@angular/core';
import { ScrollingModule } from '@angular/cdk/scrolling';
interface Row {
id: number;
title: string;
}
@Component({
selector: 'app-virtual-table',
standalone: true,
imports: [ScrollingModule],
template: `
<cdk-virtual-scroll-viewport itemSize="48" class="viewport">
<div *cdkVirtualFor="let row of rows; trackBy: trackById" class="row">
<span>{{ row.id }}</span>
<span>{{ row.title }}</span>
</div>
</cdk-virtual-scroll-viewport>
`,
styles: [`
.viewport { height: 400px; }
.row { height: 48px; display: flex; gap: 1rem; align-items: center; }
`],
})
export class VirtualTableComponent {
rows: Row[] = Array.from({ length: 50_000 }, (_, i) => ({
id: i + 1,
title: `Qator #${i + 1}`,
}));
trackById(_: number, row: Row): number {
return row.id;
}
}
Imtihonda
- Virtual scroll qachon kerak, qachon
@foryetarli? itemSizenoto'g'ri bo'lsa nima bo'ladi?- CDK virtual scroll va third-party (ngx-virtual-scroller) farqi?
Yodlash uchun
Katta ro'yxat → CDK viewport; faqat ko'rinadigan item render.
Lazy loading images — loading='lazy'
Nima bu?
Native loading="lazy" atributi — rasm viewport'ga yaqinlashganda yuklanadi. Initial page load va bandwidth tejaydi. NgOptimizedImage (@angular/common) — srcset, priority, placeholder va LCP optimizatsiyasi beradi. Above-the-fold rasmlar uchun priority ishlatiladi.
Kod misoli
import { Component } from '@angular/core';
import { NgOptimizedImage } from '@angular/common';
@Component({
selector: 'app-gallery',
standalone: true,
imports: [NgOptimizedImage],
template: `
<!-- Hero — darhol yuklash -->
<img ngSrc="/assets/hero.webp"
width="1200" height="600"
priority
alt="Bosh sahifa" />
<!-- Galereya — lazy -->
@for (photo of photos; track photo.id) {
<img [ngSrc]="photo.url"
[width]="photo.w"
[height]="photo.h"
loading="lazy"
[alt]="photo.caption" />
}
<!-- Oddiy HTML lazy (NgOptimizedImage'siz) -->
<img src="/assets/thumb.jpg" loading="lazy" alt="Miniatura" />
`,
})
export class GalleryComponent {
photos = [
{ id: 1, url: '/assets/p1.webp', w: 400, h: 300, caption: 'Manzara' },
{ id: 2, url: '/assets/p2.webp', w: 400, h: 300, caption: 'Shahar' },
];
}
Imtihonda
loading="lazy"qaysi brauzerlarda qo'llab-quvvatlanadi?NgOptimizedImagenima uchunwidth/heighttalab qiladi?- LCP (Largest Contentful Paint) uchun qanday optimizatsiya?
Yodlash uchun
Hero → priority; pastdagi rasmlar → loading="lazy".
Tree shaking — ko'p import qilmaslik
Nima bu?
Tree shaking — ishlatilmagan kod production bundle'dan olib tashlanadi. import * as _ from 'lodash' butun kutubxonani oladi; import { debounce } from 'lodash-es' faqat kerakli funksiyani. Angular standalone component'lar modul butunligini import qilmasdan faqat kerakli directive/pipe oladi. Side-effect import'lardan (import 'something') saqlaning.
Kod misoli
// ❌ Butun lodash bundle'ga tushadi
import _ from 'lodash';
const sorted = _.sortBy(users, 'name');
// ✅ Tree-shakeable
import { sortBy } from 'lodash-es';
const sorted = sortBy(users, 'name');
// ❌ Butun RxJS operators
import * as operators from 'rxjs/operators';
// ✅ Faqat keraklisi
import { map, filter, debounceTime } from 'rxjs/operators';
// Angular — faqat kerakli import
@Component({
standalone: true,
imports: [
NgIf, // faqat NgIf — butun CommonModule emas
AsyncPipe,
RouterLink,
],
})
export class LeanComponent {}
// angular.json — production optimizatsiya
{
"optimization": true,
"sourceMap": false,
"namedChunks": false,
"buildOptimizer": true
}
Imtihonda
- Tree shaking qachon ishlamaydi (side effects)?
providedIn: 'root'service tree shake bo'ladimi?- Bundle analyzer bilan qanday tekshiriladi (
ng build --stats-json)?
Yodlash uchun
Named import; standalone + selective imports; lodash-es.
