04 — Runtime и change detection: клик меняет цифру
Цель: понять, что именно происходит между «ты нажал +1» и «на экране стало 1». Это самая важная глава.
Сначала — что такое сигнал
count = signal(0) — это коробочка со значением 0, за которой Angular следит.
- Прочитать:
count()→ вернёт 0. - Поменять:
count.set(5)илиcount.update(c => c + 1).
Фокус в том, что когда ты читаешь сигнал внутри шаблона ({{ count() }}),
Angular запоминает: «этот кусок экрана зависит от этого сигнала». Поэтому при
изменении сигнала он точно знает, что обновить.
doubled = computed(() => count() * 2) — это сигнал, который сам пересчитывается,
когда меняется count. Тебе не надо его трогать руками.
Change detection = «проверить и обновить экран»
Change detection (CD) — процесс «пройтись по компонентам, посчитать свежие значения и вписать их в DOM». В Angular 21 он zoneless:
CD запускается ТОЛЬКО когда реально что-то изменилось (сигнал поменялся, пришло событие). Просто так, постоянно — не крутится.
Это отличается от старого Angular (zone.js), где CD дёргался после любого
действия (любой setTimeout, любой клик где угодно). Подробнее про разницу →
05 — OnPush и zoneless.
Анимация: полный цикл одного клика
То же самое покадрово (читай сверху вниз — это «кадры гифки»):
Кадр 1. Ты жмёшь [ +1 ]
Кадр 2. Срабатывает (click) → вызывается inc()
Кадр 3. inc() делает count.update(0 → 1)
Кадр 4. Сигнал count изменился → помечает свой <p> "грязным"
Кадр 5. Angular планирует ОДНУ проверку (tick) — не сразу, а на ближайший микротакт
Кадр 6. tick запускается:
• computed doubled пересчитывается (0→2), items (пусто→[1])
• template-функция в режиме ОБНОВИТЬ (rf & 2) проходит по компоненту
• вписывает 1 в <p>Счётчик>, 2 в <p>Удвоенный>, рисует <li>1</li>
Кадр 7. DOM обновлён. Экран: Счётчик: 1 | Удвоенный: 2 | • 1
Ключевые моменты этого цикла
1. Меняется только нужное
template-функция в режиме «обновить» сравнивает старое значение с новым и трогает
DOM только если значение поменялось. <h1>demo21</h1> не менялся — его никто не
перерисовывает.
2. computed «бесплатные»
Тебе не надо обновлять doubled и items вручную. Они зависят от count, и при
чтении в режиме «обновить» сами берут свежее значение. Поменял count — всё
остальное подтянулось.
3. Одна проверка на всё
Если в одном обработчике ты поменяешь count три раза, Angular не запустит CD
три раза. Он запланирует одну проверку и сделает её один раз. Это экономит работу.
4. Что НЕ запускает CD в zoneless
setTimeout(() => { this.x = 5; }); // x — обычное поле, не сигнал
Это НЕ обновит экран! Потому что x — не сигнал, Angular о нём не знает, и проверку
никто не запланировал. Это главная ловушка при переходе на zoneless — см.
главу 05. Чтобы заработало — сделай x сигналом.
Пример с порогом: count 2 → 3
Когда count переваливает за 2, в режиме «обновить» срабатывает @if (count() > 2),
и блок «Больше двух!» создаётся прямо сейчас (вызывается режим «создать» для
этого кусочка):
count = 2: Счётчик: 2 | Удвоенный: 4 | • 1 • 2
↓ клик
count = 3: Счётчик: 3 | Удвоенный: 6 | "Больше двух!" | • 1 • 2 • 3
↑ @if смонтировал блок
↑ @for добавил <li>3
Видишь: @if/@for создают и удаляют куски DOM по ходу, точечно, ровно когда
данные этого требуют. Это и есть «работа» приложения.
Мини-словарь этой главы
- tick — один запуск проверки «обновить экран».
- «грязный» (dirty) — пометка «этот компонент надо проверить».
- zoneless — режим, где проверка запускается только от сигналов/событий, а не постоянно.
Дальше: когда именно Angular проверяет компонент, а когда пропускает (OnPush) → 05 — OnPush и zoneless.