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

Живые supply в действии

Поскольку живой supply вещает тем подключениям, которые слушают в данный момент, за одним и тем же потоком могут следить сразу несколько слушателей, и каждый волен присоединиться или уйти когда угодно. Здесь за потоком событий наблюдают двое: log, который записывает всё, и alert, который присоединяется позже и уходит раньше.

my $supplier = Supplier.new;
my $events   = $supplier.Supply;

my $log = $events.tap(-> $v { say "log:   $v" });    # присоединяется первый слушатель
$supplier.emit('start');

my $alert = $events.tap(-> $v { say "alert: $v" });  # присоединяется второй слушатель
$supplier.emit('warning');
$supplier.emit('all clear');

$log.close;                                          # первый слушатель уходит
$supplier.emit('stop');

Программа печатает:

log:   start
log:   warning
alert: warning
log:   all clear
alert: all clear
alert: stop

Жизненный цикл двух подключений выстраивается так: 🟢 отмечает присоединение подключения, 🔴 — его уход, а ✅ — каждое значение, которое подключение действительно получило:

Шаг log alert
$events.taplog 🟢 присоединяется
emit 'start' ✅ start
$events.tapalert 🟢 присоединяется
emit 'warning' ✅ warning ✅ warning
emit 'all clear' ✅ all clear ✅ all clear
$log.close 🔴 уходит
emit 'stop' ✅ stop

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

  • .tap возвращает объект Tap — рукоятку, которую вы сохраняете, чтобы управлять именно этой подпиской.
  • start выдаётся, когда слушает только log, поэтому его видит только log. Это снова правило живого supply: alert присоединился после start, а живой supply прошлое не проигрывает, так что alert этого значения никогда не увидит.
  • warning и all clear выдаются, когда подключены оба, поэтому каждое значение доходит до обоих — в том порядке, в каком они подписались: сначала log, затем alert.
  • Вызов $log.close отсоединяет от supply. С этого момента log не получает ничего, поэтому последнее stop доходит только до alert.

Отсюда два вывода. Во-первых, один живой supply способен разветвляться сразу на множество независимых подключений. Во-вторых, каждое подключение — отдельная подписка со своим временем жизни: сохраните объект Tap, который возвращает .tap, и вы сможете прекратить именно этого слушателя методом .close, не потревожив остальных.

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

Живые supply   |   Два подключения


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