Войти Регистрация
Фронтенд

93. Плеер Яндекс Музыки на сигналах: signal, computed и effect

Сложная

Состояние веб-плеера Яндекс Музыки — десяток связанных значений: громкость, mute, позиция трека, номер в очереди. Подписки руками рвутся при каждом рефакторинге, поэтому хотят сигналы, как в Solid и Preact Signals.

Напишите createReactive(), которая возвращает { signal, computed, effect }. signal(v) → [get, set]; set того же значения (Object.is) ничего не делает. computed(fn) → геттер: считает fn лениво, при первом чтении, и кэширует до изменения зависимостей. effect(fn) запускает fn сразу и снова после изменений того, что fn читала; возвращает функцию отписки.

Три требования. Зависимости собираются заново на каждом запуске: если fn прочитала muted() и вышла, громкость её не будит. Если computed пересчитался в то же значение, эффекты ниже не перезапускаются. На один set эффект срабатывает один раз и видит согласованные значения: при секундах 130 таймер показывает «2:10», а не «2:5» по дороге.

Все set синхронные, эффекты отрабатывают до возврата из set. Тест вызывает сценарий по имени, код сценариев открыт в harness.

В работе: Веб-плеер: таймер трека, громкость и кнопка «Следующий» пересчитываются от 4 сигналов без лишних перерисовок.

Пример 1: эффект и повтор того же значения

Аргументы теста
"effect"
Ожидается
["громкость 50", "громкость 70", "громкость 0"]

Пример 2: computed ленивый и с кэшем

Аргументы теста
"lazy"
Ожидается
["до чтения 0", "50 50 runs=1", "после set 1", "60 runs=2"]
Как проверяем Объявите createReactive — тест вызывает её сам. Таймеры и Date в тестах ненастоящие: время идёт по команде теста, поэтому setTimeout на 5 секунд проверяется мгновенно. Тестов 7: 2 открыты выше, остальные приходят после старта подхода. Лимит — 2 с на тест.
function createReactive() // → { signal(v) → [get, set], computed(fn) → get, effect(fn) → dispose }
реактивностьграфы зависимостейзамыкания

Источник: на задачах Яндекс Музыки: состояние веб-плеера. Условие пересказано своими словами.