01 — Компиляция: из шаблона в JS-функцию
Цель главы: понять, что твой шаблон не доезжает до браузера как HTML. Он превращается в обычную JavaScript-функцию ещё на твоём компьютере.
Проблема, которую решает компилятор
Браузер понимает только две вещи:
- JavaScript (логика);
- DOM (дерево HTML-элементов: создать
<p>, поменять текст, удалить).
А ты пишешь вот это:
<p>Счётчик: {{ count() }}</p>
@if (count() > 2) { <p class="big">Больше двух!</p> }
Браузер не знает, что такое {{ }} и @if. Значит, кто-то должен это перевести
в «создай <p>, положи туда число, а вон тот блок показывай только если count > 2».
Этим занимается компилятор Angular — и делает он это заранее, при сборке (AOT —
Ahead Of Time, «заранее»).
Что получается на выходе
Каждый компонент превращается в вызов ɵɵdefineComponent({...}), внутри которого —
template-функция. Упрощённо она выглядит так:
function App_Template(rf, ctx) {
if (rf & 1) { // режим СОЗДАТЬ (первый раз)
element('p'); // создать <p>
text(1); // создать пустой текстовый узел внутри
}
if (rf & 2) { // режим ОБНОВИТЬ (каждый раз потом)
advance(1);
textInterpolate1('Счётчик: ', ctx.count(), ''); // вписать число
}
}
Запомни эти два режима — это сердце всего Angular:
rf & 1— create (создание). Выполняется один раз: строит DOM-каркас.rf & 2— update (обновление). Выполняется при каждой проверке: вписывает свежие значения в уже существующий DOM.
Одна и та же функция и строит, и обновляет — просто в разных режимах. Поэтому Angular не перерисовывает всё заново, а точечно меняет текст/атрибуты.
Анимация: путь шаблона по конвейеру
Если кадры не проигрались, вот то же самое по шагам (это и есть «кадры»):
Кадр 1: "<p>Счётчик: {{ count() }}</p>" ← просто строка
Кадр 2: HTML-дерево: <p> ─ text("Счётчик: ") ─ {{ }} ← разобрали теги
Кадр 3: список операций: [создать <p>] [создать text] [обновить text = count()]
Кадр 4: числа вместо имён: слот 0 = <p>, слот 1 = text
Кадр 5: готовые вызовы: element('p'); textInterpolate1('Счётчик: ', count())
Каждый кадр — это отдельная стадия компилятора. Их там около 70, но идея одна: строка → дерево → список простых операций → JS-инструкции.
Что станет с нашими конструкциями
| Ты написал | Во что превратится | Простыми словами |
|---|---|---|
{{ count() }} |
textInterpolate1(..., count()) |
«впиши число в текст» |
(click)="inc()" |
listener('click', () => inc()) |
«повесь обработчик клика» |
@if (count() > 2) |
conditional(count() > 2 ? 0 : -1) |
«показывай блок 0 или ничего» |
@for (n of items()) |
repeater(items()) |
«повтори блок для каждого элемента» |
Заметь: @if и @for — это не магия в браузере. Это обычные функции
conditional и repeater, которые создают/удаляют куски DOM по условию.
Важный вывод
После компиляции в браузер едет только JavaScript. Никаких {{}}, @if,
@for там уже нет — есть функция, которая знает, что и когда нарисовать. Поэтому
Angular-приложение стартует быстро: браузеру не надо «разбирать шаблоны», всё уже
переведено.
Дальше: эту функцию (и весь остальной код) надо упаковать в файл, который скачает браузер → 02 — Build.