Сигналы Angular¶
30.09.2026
Сигналы Angular детально отслеживают, где и как в приложении используется состояние, и за счёт этого фреймворк оптимизирует обновление отрисовки.
Перед этим подробным руководством загляните в основы сигналов.
Что такое сигналы?¶
Сигнал — обёртка над значением. Когда значение меняется, сигнал уведомляет тех, кто его читает. В сигнале может лежать что угодно: от примитива до сложной структуры данных.
Значение читают вызовом геттера: так Angular отслеживает, где сигнал используется.
Сигнал бывает записываемым или только для чтения.
Записываемые сигналы¶
У записываемого сигнала есть API, которым значение меняют напрямую. Такой сигнал создают функцией signal, передав начальное значение:
1 2 3 4 | |
Значение меняют напрямую через .set():
1 | |
или считают новое из предыдущего через .update():
1 2 | |
Тип записываемого сигнала — WritableSignal.
Записываемый сигнал только для чтения¶
У WritableSignal есть метод asReadonly(). Он возвращает версию сигнала только для чтения. Так значение отдают потребителям и не дают менять его напрямую:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | |
Сигнал только для чтения повторяет изменения исходного записываемого сигнала, но методы set() и update() его не меняют.
У сигнала только для чтения нет встроенной защиты от глубокого изменения значения.
Вычисляемые сигналы¶
Вычисляемые сигналы доступны только для чтения: их значение выводится из других сигналов. Такой сигнал задают функцией computed и функцией вычисления:
1 2 | |
Сигнал doubleCount зависит от count. Когда count обновляется, Angular знает, что doubleCount тоже пора обновить.
Вычисляемые сигналы ленивы и кэшируют результат¶
Функция вычисления doubleCount не запускается, пока doubleCount не прочитают в первый раз. Результат кэшируется. Повторное чтение возвращает кэш и ничего не пересчитывает.
Если затем изменить count, Angular считает кэш doubleCount недействительным. Следующее чтение посчитает новое значение.
Поэтому в вычисляемом сигнале можно спокойно делать дорогие вычисления, например фильтровать массивы.
Вычисляемый сигнал нельзя записывать¶
В вычисляемый сигнал нельзя записать значение напрямую. Вызов
1 | |
не компилируется: doubleCount — не WritableSignal.
Зависимости вычисляемого сигнала динамические¶
Отслеживаются только сигналы, которые действительно прочитали во время вычисления. В этом computed сигнал count читается, только если сигнал showCount истинен:
1 2 3 4 5 6 7 8 9 | |
Если при чтении conditionalCount сигнал showCount равен false, возвращается сообщение «Nothing to see here!», а сигнал count не читается. Поэтому последующее изменение count не пересчитает conditionalCount.
Если установить showCount в true и снова прочитать conditionalCount, вычисление выполнится заново, пойдёт по ветке с истинным showCount и вернёт сообщение со значением count. После этого изменение count сбросит кэш conditionalCount.
Зависимость во время вычисления можно не только добавить, но и убрать. Если позже вернуть showCount в false, count перестанет быть зависимостью conditionalCount.
Реактивные контексты¶
Реактивный контекст — состояние среды выполнения, в котором Angular следит за чтением сигналов и строит зависимость. Код, который читает сигнал, — потребитель, а читаемый сигнал — производитель.
Angular автоматически входит в реактивный контекст, когда:
- выполняется обратный вызов
effectилиafterRenderEffect; - вычисляется сигнал
computed; - вычисляется
linkedSignal; - вычисляется функция
paramsили загрузчикresource; - рендерится шаблон компонента, включая привязки свойства хоста.
Во время этих операций Angular создаёт живую связь. Если отслеживаемый сигнал изменится, Angular со временем снова выполнит потребителя.
Проверка реактивного контекста¶
Вспомогательная функция assertNotInReactiveContext проверяет, что код выполняется не внутри реактивного контекста. Передайте ссылку на вызывающую функцию: если проверка не пройдёт, сообщение об ошибке укажет на нужную точку входа API. Такое сообщение понятнее общей ошибки реактивного контекста и сразу показывает, что исправлять.
1 2 3 4 5 6 | |
Чтение без отслеживания зависимостей¶
Иногда код внутри реактивной функции вроде computed или effect читает сигналы, но зависимость от них создавать не нужно.
Допустим, при смене currentUser нужно записать в журнал значение counter. Можно создать effect, который читает оба сигнала:
1 2 3 | |
Сообщение появится, когда изменится любой из сигналов currentUser и counter. Если эффект должен срабатывать только при смене currentUser, чтение counter побочное: изменение counter не должно давать новую запись.
Чтобы чтение не отслеживалось, геттер вызывают через untracked:
1 2 3 | |
untracked также нужен, когда эффект вызывает внешний код, который не должен становиться зависимостью:
1 2 3 4 5 6 7 8 | |
Реактивный контекст и асинхронные операции¶
Реактивный контекст действует только в синхронном коде. Чтение сигнала после асинхронной границы зависимостью не станет.
1 2 3 4 5 | |
Чтобы чтение отслеживалось, сигнал читают до await. Это касается и аргументов ожидаемой функции: они вычисляются синхронно.
1 2 3 4 5 | |
1 2 3 4 | |
Сложные вычисления¶
computed закрывает простые вычисления только для чтения. Иногда нужно записываемое состояние, которое зависит от других сигналов. Подробнее — в руководстве Зависимое состояние через linkedSignal.
Все API сигналов синхронны: signal, computed, input и остальные. Приложению часто нужны данные, которые появляются асинхронно. Resource встраивает такие данные в код на сигналах и оставляет синхронный доступ к результату. Подробнее — в руководстве Асинхронная реактивность через ресурсы.
Побочные эффекты для нереактивных API¶
На смену состояния лучше отвечать синхронным или асинхронным вычислением. Этого хватает не всегда: иногда на изменение сигнала нужно ответить через API, который сам по себе не реактивен. Для таких случаев берите effect или afterRenderEffect. Подробнее — в руководстве Побочные эффекты для нереактивных API.
Чтение сигналов в компонентах OnPush¶
Если сигнал читают в шаблоне компонента со стратегией OnPush, Angular записывает его в зависимости этого компонента. Когда значение меняется, Angular автоматически помечает компонент, и тот обновится при следующем обнаружении изменений. Подробнее о компонентах OnPush — в руководстве Пропуск поддеревьев компонентов.
Дополнительные темы¶
Функции равенства сигнала¶
При создании сигнала можно передать функцию равенства. Она проверяет, отличается ли новое значение от предыдущего.
1 2 3 4 5 6 7 8 | |
Функцию равенства принимают и записываемые, и вычисляемые сигналы.
По умолчанию сигналы сравнивают значения по ссылке (сравнение Object.is()).
Проверка типа сигнала¶
Функция isSignal проверяет, является ли значение сигналом Signal:
1 2 3 4 5 6 | |
Проверить, что сигнал именно записываемый, можно через isWritableSignal:
1 2 3 4 5 | |
Сигналы вместе с RxJS¶
Как сигналы стыкуются с RxJS, разобрано в руководстве Совместимость RxJS с сигналами Angular.
Источник: https://angular.dev/guide/signals