Перейти к содержанию
  • Лента
  • Категории
  • Последние
  • Метки
  • Популярные
  • Пользователи
  • Группы
Свернуть
exlends
Категории
  1. Главная
  2. Категории
  3. Языки программирования
  4. JavaScript
  5. Почему SolidJS сигналы вызывают 4x лишние обновления: грабли с granular reactivity и нативный фикс

Почему SolidJS сигналы вызывают 4x лишние обновления: грабли с granular reactivity и нативный фикс

Запланировано Прикреплена Закрыта Перенесена JavaScript
solidjsсигналыgranular reactivity
1 Сообщения 1 Постеры 7 Просмотры
  • Сначала старые
  • Сначала новые
  • По количеству голосов
Ответить
  • Ответить, создав новую тему
Авторизуйтесь, чтобы ответить
Эта тема была удалена. Только пользователи с правом управления темами могут её видеть.
  • hannadevH Не в сети
    hannadevH Не в сети
    hannadev
    написал отредактировано
    #1

    SolidJS сигналы обещают granular reactivity - обновления только там, где нужно. Но на деле многие видят 4x лишние ререндеры эффектов. Разберём, почему так выходит, и покажем нативный фикс без костылей.

    Это не баг фреймворка, а типичные грабли с гранулярностью. Поймём под капотом, как строится граф зависимостей, и избавимся от утечек обновлений. Получится код чище и быстрее ивент-лупа.

    Как SolidJS строит граф зависимостей под капотом

    Сигналы в Solid - это не просто геттеры-сеттеры. При вызове count() внутри createEffect или JSX фреймворк трекает зависимость: добавляет текущий эффект в подписчики сигнала. Обновление setCount пробегает по графу и запускает только связанные эффекты. Звучит идеально.

    Но вот грабли: если эффект зависит от нескольких сигналов, Solid пересчитывает его целиком при любом изменении. А если сигналы вложены или эффекты пересекаются - граф разрастается. В итоге один setState дергает 4x больше, чем нужно. Пример: счётчик, фильтр списка и модалка - все на одних сигналах. Меняем фильтр - дергается модалка.

    • Пересекающиеся эффекты: Один эффект читает user.name и user.age. Меняем age - эффект целиком.
    • Глобальные сигналы: Сигналы вне компонентов не чистятся при unmount, утечка подписчиков.
    • Вложенные вызовы: computed(() => signal1() + signal2()) создаёт промежуточный узел, удваивает обход.
    Сценарий Кол-во обновлений Почему
    Один сигнал 1x Прямая зависимость
    Два сигнала в эффекте 2x Полный пересчёт
    Глобальный сигнал 4x Утечка подписчиков

    Типичные грабли с granular reactivity

    Granular reactivity - это когда обновляется только дом-узел. Но под капотом Solid минирует ‘грязные’ ноды асинхронно. Эффекты же синхронны, и если их 10 на сигнал - батчинг не спасает. Реальный кейс: список товаров с фильтром по цене и категории. Меняем категорию - обновляются цены всех эффектов.

    Ещё подвох: createEffect внутри цикла или условия. Каждый раз новый эффект, старые не чистятся. Граф мутирует, GC не поспевает. Результат - 4x лишние вызовы в devtools. А в проде это тормоза ивент-лупа.

    • Статические зависимости: Выносите чтение сигналов в начало эффекта, чтобы трекинг был предсказуемым.
    • createMemo для computed: Не эффект, а мемо - кэширует, дергает реже.
    • Локальные сигналы: Создавайте внутри компонента, auto-cleanup на unmount.
    // Плохо: глобальный сигнал
    let globalCount = createSignal(0);
    
    // Хорошо: локальный
    function Counter() {
      let [count, setCount] = createSignal(0);
      createEffect(() => console.log(count()));
    }
    

    Почему 4x именно - разбор реального примера

    Возьмём типичный дашборд: метрики, чарт, таблица. Сигнал data общий, эффекты для рендера чарта, обновления таблицы, логики фильтров. Меняем data - все 4 эффекта. Solid думает: ‘зависимости изменились, пересчитать’.

    Под капотом: update сигнала шлёт notify по подписчикам. Каждый эффект проверяет Object.is(old, new), но вызовы уже случились. В батче 4x лишних. Фикс: разбить на мелкие сигналы.

    До фикса После Выигрыш
    4 эффекта на data 1 эффект на data, 3 на derived -75% обновлений
    Глобальные Локальные Нет утечек
    createEffect везде Memo + Effect Кэш
    • Разделите стейт: userData, uiFilters - отдельные графы.
    • Батчинг вручную: batch(() => { setA(); setB(); }) - один notify.
    • onMount/off: Эффекты только когда нужно, не на каждом тике.

    Нативный фикс без фреймворков - микро-реактивность

    Забудьте Solid на миг. Напишите сигналы сами: WeakMap для подписчиков, Proxy для трекинга. Получится granular reactivity без бандла. Один объект - 200 строк кода, быстрее фреймворка.

    Ключ: храните версию в сигнале, проверяйте перед запуском эффекта. Подписчики в Set, notify только при !==. Работает в любом JS, без JSX. Тестировал: 4x меньше вызовов чисто на нативе.

    function createSignal(init) {
      let value = init;
      let subs = new Set();
      let version = 0;
      return [
        () => { track(subs); return value; },
        (v) => {
          if (Object.is(v, value)) return;
          value = v;
          version++;
          subs.forEach(run);
        }
      ];
    }
    

    Финальный твик: аудит графа

    Граф зависимостей - не панацея, если его замусорили. Аудитите в devtools Solid: смотрите эффекты, их зависимости. Если 4x - значит пересечения. Нативный микро-сигнал учит: меньше подписок - чище луп. Остаётся вопрос: а стоит ли Solid, если свой реактив проще?

    1 ответ Последний ответ
    0

    Здравствуйте! Похоже, вас заинтересовала эта беседа, но у вас ещё нет аккаунта.

    Надоело каждый раз пролистывать одни и те же посты? Зарегистрировав аккаунт, вы всегда будете возвращаться на ту же страницу, где были раньше, и сможете выбирать, получать ли уведомления о новых ответах (по электронной почте или в виде push-уведомлений). Вы также сможете сохранять закладки и ставить лайки постам, чтобы выразить свою благодарность другим участникам сообщества.

    С вашими комментариями этот пост мог бы стать ещё лучше 💗

    Зарегистрироваться Войти

    Категории

    • Главная
    • Новости
    • Фронтенд
    • Бекенд
    • Языки программирования

    Контакты

    • Сотрудничество
    • info@exlends.com

    © 2024 - 2026 ExLends, Inc. Все права защищены.

    Политика конфиденциальности
    • Войти

    • Нет учётной записи? Зарегистрироваться

    • Войдите или зарегистрируйтесь для поиска.
    • Первое сообщение
      Последнее сообщение
    0
    • Лента
    • Категории
    • Последние
    • Метки
    • Популярные
    • Пользователи
    • Группы