惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Hugging Face - Blog
Hugging Face - Blog
腾讯CDC
阮一峰的网络日志
阮一峰的网络日志
博客园_首页
Last Week in AI
Last Week in AI
月光博客
月光博客
D
DataBreaches.Net
WordPress大学
WordPress大学
雷峰网
雷峰网
酷 壳 – CoolShell
酷 壳 – CoolShell
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
博客园 - 叶小钗
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
U
Unit 42
Recent Announcements
Recent Announcements
宝玉的分享
宝玉的分享
MyScale Blog
MyScale Blog
C
Check Point Blog
F
Fortinet All Blogs
B
Blog
小众软件
小众软件
Vercel News
Vercel News
罗磊的独立博客
有赞技术团队
有赞技术团队

Все публикации подряд на Хабре

Ловим музу за клавиатуру: как айтишнику стать автором Что умеет Midjourney в 2026? Мой немного грустный разбор этого шикарного инструмента Никто не любит писать тесты, но ИИ может исправить это IPv8 выглядит как мечта. Поэтому почти наверняка не взлетит Производители вернули в продажу материнки с DDR3. Что происходит? Управление агентом с телефона через Telegram теперь в KodaCode От координации к лидерству: как меняется роль руководителя разработки Я сделала родителям бизнес вместо пенсии: зарабатываем 70 тысяч, мама не даёт продать В три раза быстрее приемка товара и оптимизация трудозатрат на 73%: как «РСТ-Инвент» помог Gulliver Group ИИ-шечный мир победил? О влиянии искусственного интеллекта на игропром Кремль снижает давление на Телеграмм пока Европа строит интернет по паспорту Как CEO, CTO и CIO за 8 часов собрали ИИ-директора, который умеет держать позицию под давлением Как (не) потерять домен за выходные Вместо 8 разных VPS: как я организовал практику студентам на одном сервере Почему твой Open Source проект не замечают? R&D: искусство управления неопределенностью в разработке AI-дефляция: вакансий для разработчиков больше, а рост зарплат — худший за 15 лет Мы отдали управление роботами OpenClaw. Что из этого вышло Галактический ID: система идентификации для всех форм разумной жизни Шесть основ бизнес-анализа: начинаем с вопроса «Кто в игре?» Код-ревью, в котором дело не в коде Данные переехали. Команда — нет Системной подход к сдаче OSWE в 2025 Почему комната управления реактором покрашена в цвет морской пены 4 YAML-файла вместо PySpark: как аналитикам строить пайплайны без разработчиков LLM-агент для поиска свободных доменов: автоматизируем подбор Когда, зачем и как правильно начинать новую сессию в Claude Code? Как я заставил нейросеть писать макросы для FreeCAD Анатомия ИИ‑агента для подбора персонала. От тысячи резюме к топ‑10 за минуты Опыт разработчика как экономика внимания
Исключения в реактивных системах
Дмитрий Карловский · 2026-06-19 · via Все публикации подряд на Хабре

Исключения в реактивных системах

Средний

4 мин

527

Очень часто программисты не думают о чрезвычайных ситуациях. Особенно печально, когда это не разработчики приложений, а авторы библиотек и фреймворков.

Например, когда я готовил этот материал, я спросил в чате Effector, как система ведет себя при возникновении исключений. На что мне ответили, что в чистых функциях не должно быть исключений (кстати, исключения на самом деле не противоречат чистоте, но это другая история), и если ты их допустил, то ты сам дурак. Когда я спросил, знает ли автор, как его библиотека поведет себя в чрезвычайной ситуации, меня обвинили в токсичности и забанили.

Ошибок тоже не должно быть, как и других неприятностей в жизни, однако они иногда случаются. Вина ли это программиста, браузера, его расширений, операционной системы, звездного ветра — неважно. Нужно уметь принимать удар и не прятать голову в песок. Но в разных реактивных библиотеках мы столкнемся с разным поведением…

🎲 Unstable: Нестабильная работа
⛔ Stop: Остановка работы
🔙 Revert: Откат к стабильному состоянию
🦺 Store: Индикация ошибки и ожидание восстановления

🎲 Unstable: Нестабильная реактивность

Часто при возникновении исключения приложение переходит в неконсистентное состояние, что приводит к нестабильной работе.

В примере, допустим, в имя закрался некорректный codepoint. И, скажем, попытка взять длину строки в этом случае приводит к исключению. Пример довольно синтетический, позже я покажу более реалистичные, а пока так.

Итак, при вычислении инварианта произошло исключение, из-за чего runtime не обновил Count. В результате все состояния разделились на 2 подграфа, которые сами по себе консистентны, но уже не согласованы друг с другом.

⛔ Stop: Остановка реактивности

Не менее странное решение — просто прекратить работу, как, например, делает RxJS. Если в потоке где-то возникает исключение, то все последующие потоки завершаются и больше не работают.

Эта стратегия подходит для одиночной задачи — либо ты ее выполняешь, либо падаешь с ошибкой. Но реактивность предназначена для долгоживущих систем, которые постоянно что-то отображают. Это значит, что если реактивность сломается, приложение просто сломается без уведомления пользователя.

Более того, оно сломается только наполовину. А чтобы восстановить работу, придется перезапускать либо все приложение, либо хотя бы эту половину.

Случай из жизни: на моем этаже в отеле поселилась толпа спортсменов. И это ребята под 100 кг чистого мяса. И вот как-то утром мы втиснулись с ними в лифт, что предсказуемо привело к перегрузке. Лифт поднял лапки и сказал “все”.

Ну, ладно, пара вышла — ничего не произошло. Половина вышла — все равно ничего. Все вышли — лифт все равно не заработал. И нам всем пришлось бежать по лестнице. Думаю, софт для этого лифта писали на RxJS, не иначе.

🔙 Revert: Откат к стабильному состоянию

Некоторые библиотеки, в принципе, не допускают неконсистентности, пересчитывая инварианты в рамках транзакции. Так что если что-то идёт не так, все состояния откатываются к последнему консистентному.

Формально звучит неплохо. Но для пользователя это ужасное поведение, потому что из-за одной дряной овцы где-то в углу приложения, которая постоянно выбрасывает исключения, все приложение встает колом и никак не реагирует на действия пользователя. Или проще говоря — оно крепко зависает. Что нехорошо.

🦺 Store: Индикация ошибки и ожидание восстановления

Гораздо практичнее рассматривать ошибку как возможный результат вычисления наряду с возвращаемым значением.

Здесь все состояния, зависящие от некорректного, тоже помечаются как некорректные. И система рендеринга может автоматически показывать индикатор ошибки для частей приложения, которые не удалось обновить. Либо можно поймать исключение и нарисовать свое красивое сообщение. В любом случае пользователь поймет, что происходит и что на сломанную часть приложения полагаться не стоит. Но другие части можно продолжать использовать.

Хотя часть приложения сломана, состояние приложения остается консистентным. Потому что сообщение об ошибке на выходе согласовано с некорректным значением на входе.

При этом устранение причины сбоя автоматически восстановит корректную работу этой части приложения. Без дополнительных действий со стороны программиста!

Именно эта стратегия и используется в $mol_wire - самом продвинутом реактивном рантайме.

Исключения в $mol_wire

Реактивное состояние может принимать один из 3 возможных типов значений:

  • Result — фактическое валидное значение.

  • Error — информация об исключении.

  • Promise — обещание, что скоро появится либо значение (Result), либо объяснение, почему его нет (Error).

Эти значения могут поступать следующими способами:

  • return — значение, возвращаемое функцией.

  • throw — прерывание выполнения.

  • put — прямое запись значения в кэш.

В данном случае неважно, каким способом мы доставили значение — оно записывается в кэш. При доступе к состоянию поведение зависит только от типа значения:

  • Ошибки и промисы выбрасываются через throw.

  • Остальные значения возвращаются через return.

class MyModel extends Object {

  // throws Promise or Error
  @act fetchJSON( url: string ): object {
    return fetch( url ).then( resp => res.json() ) // return Promise
  }

  // throws Promise
  @mem profile(): { name: string } {
    try {
      return this.fetchJSON( '/profile' ).user
    } catch( error ) {
      if( 'then' in error ) throw error // catch & throw Promise
      return { name: 'unknown' }
    }
  }

  // throws Promise
  @mem name(): string {
      return this.profile().name // bypass Promise
  }
  
}

То есть реактивная мемоизация методов не совсем прозрачна: если вы вернете экземпляр Error, он все равно будет выброшен позже, а если вы выбросите, например, строку, она все равно будет возвращена позже. Получается своего рода нормализация поведения.

Конечно, можно было бы сделать прозрачное поведение, но в JS у нас уже есть нормализация с асинхронными функциями: что бы мы ни возвращали или кидали, они всегда возвращают промис. А промисы, кстати, в нашем случае нужно не возвращать, а выбрасывать, но об этом в другой раз.

А пока, подписывайтесь на что-нибудь, вступайте во что-то там, и держите руку на пульсе вот этого вот.