delay, spaceBy & sample
Three ways to move events around in time: shift them all, spread them out, or read only the newest on a fixed clock.
Lecture
Rate limiting always costs you something, and the only real question
is what. throttle
and debounce pay in
events: they keep one per window and drop the rest,
which is right when the events are samples of a continuous thing and
an old one is worthless. spaceBy(gap) pays in
time instead: every event survives, queued and
released one per gap, which is right when each event is a
discrete instruction you must not lose — six messages to send against
an API that allows one call per 100ms.
That trade has a sharp edge. Because spaceBy queues
rather than drops, a source that produces faster than
gap forever grows an unbounded queue. It is for
bursts — a batch that arrives at once and must all get
through — not for genuinely endless input, where throttle's
lossiness is a feature.
delay(duration) is the simplest of the three: the entire
stream is shifted by a fixed amount, spacing intact, nothing dropped.
The close waits for the last delayed event to land, so nothing is
lost at the end; errors are forwarded immediately, since only data is
worth holding.
sample(period) is
sampleOn with the clock built
in — the newest value every period, silent when nothing
new has arrived. Reach for it when the source is a state-like feed
(a position, a temperature, a scroll offset) and the consumer has its
own refresh rate. fxdart events layer, after Rx's delay,
interval and sampleTime.
Demo 1 · Pacing a burst, losslessly
Demo 2 · Shifting, and reading on a clock
Try it yourself
Exercise: a send rate and a reporting rate, in one chain.
throttle — the lossy counterpart: one event per window, immediately ·
debounce — wait for the burst to end, then take its last value ·
chunkEvery — keep every event too, but grouped rather than spread out