Курс языка программирования Raku / Функциональное, конкурентное, реактивное и веб-программирование / Реактивное программирование / react и whenever

Два таймера

Во всех примерах с react до сих пор использовался Supply.from-list, который выталкивает все свои значения в тот же миг, как к нему подключились. Поэтому каждый поток печатался целиком, прежде чем начинался следующий, — никакого ожидания не было. Настоящие потоки событий устроены иначе: их значения приходят растянутыми во времени, и блок react переплетает их по мере поступления.

Простейший поток с таким поведением — таймер. Supply.interval($period) выдаёт растущий счётчик — 0, 1, 2, … — раз в $period секунд. Запустите два таких таймера с разной частотой внутри одного react, и их значения сплетутся:

react {
    whenever Supply.interval(0.3) {
        say "tick $_";
    }
    whenever Supply.interval(0.5, 0.25) {
        say "TOCK $_";
    }
    whenever Promise.in(1.4) {
        done;
    }
}

Типичный запуск печатает:

tick 0
TOCK 0
tick 1
tick 2
TOCK 1
tick 3
tick 4
TOCK 2

Быстрый tick срабатывает каждые 0.3 секунды, более медленный TOCK — каждые 0.5, начиная с четверти секунды (второй аргумент interval и есть эта начальная задержка). Ни один не ждёт другого: блок react просто выполняет то тело whenever, которому соответствует пришедшее значение, поэтому два потока пересекаются, а не сменяют друг друга.

Поскольку таймеры сами по себе никогда не заканчиваются, выход обеспечивает третий whenever: Promise.in(1.4) исполняется через 1,4 секунды, и его тело вызывает done, завершая блок react. Без него react тикал бы и такал вечно.

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

Навигация по курсу

whenever и when   |   Верхний регистр с react


💪 Или перейдите сразу к упражнениям этого раздела.