Push and pull
Data sources are often modelled as either a push or pull.
For example, in Javascript DOM events, if you want the position of the cursor, it needs to be pushed to you via an event handler. You can’t pull the values at any time.
-
Push is characterised as being event-driven, where the source seems more in control. You’ll see this in DOM events, but is also akin to physical metaphors like parcel delivery. It tends to be that values gets pushed when they change.
-
Pull is more receiver-oriented, requesting values when it wants. For example, read the value of an analog pin on a microcontroller or checking your mailbox to see if there’s mail.
Sources might be inherently - or logically - push or pull, and it’s worth being aware when you’re fighting against its logic. And if so, what challenges this poses.
Polling
It’s common to poll pull sources - continually read the value and take action based on the current value or when it changes.
A challenge when polling is choosing how often to do so. This will usually be a trade-off between latency and resource usage.
A high polling rate (ie. reading very fast) will lower latency, giving values which more closely match the source. However, the device will end up spending a lot time reading data, leaving less resources for processing the data or using it constructively.
In cases where data sources don’t change often, but could in principle change at any time (eg pressing a mouse button), it becomes very difficult to imagine a perfect polling strategy. We’d be checking all the time if a button is pressed, but really we only want to know when it is pressed.
It’s a bit like going to a parcel pickup location every day in case a parcel is available for you (polling) versus waiting for a notification that a parcel is ready for pickup (push).
Adapting
Sometimes we have a push source we want to use as a pull, or vice versa.
From push to pull
Let’s convert a push event into something that can be pulled:
Now we have a pull function to call, getLastCoord
where we can read the last pointer coordinate (or of course we could access the variable lastCoord
directly).
This can be implemented efficiently, with little trade-offs in terms of performance or code.
From pull to push
Converting from a pull to push is where things get more challenging.
Based on polling, we can run a callback when the value changes:
Now we have push-style access:
We could also push values based a different logic - for example sending a value when a threshold is reached, or only when it changes by a certain amount.
As described earlier under Polling, a challenge is in setting the right polling rate. In the above example, we poll at a constant 5ms rate. But this is regardless of whether the monitorSensor
callback cares about values at that time.
The ixfx Reactive pattern allows for push (and sometimes pull) semantics. Generators are interesting in allowing a hybrid of push and pull.