I'm logging banner impressions when it is visible on screen.
When a user scrolls, the same banner can be made visible multiple times in short time period.
And I'd like to prevent that.
On first thought, throttle
is perfect way of preventing it.
But then when you have multiple banners in one page, throttle
would not log the 2nd banner in screen if throttled.
So how can I throttle per key? (banner id as a key in this example) ie, I want to throttle banner impression per banner_id. (it's like servers throttling api_endpoint access per api keys)
EDIT
One could think of creating throttle
for each key, but wonder if it could take up too much resources?
I wonder how API libraries such as Django-rest-framework implements throttle per api key. I guess it could be totally different from what saga throttle does.
Things like django-rest
use expirable map for throttling. An expirable set is sufficient for the task, too.
I cannot recommend an exact npm module for expirable map/set, unfortunately.
The pseudocode:
function* throttlePerKey(pattern, selector, timeout, saga) {
const set = new ExpirableSet({ expire: timeout })
while(true) {
const action = yield take(pattern)
const id = selector(action)
const throttled = set.has(id)
if (throttled) {
// Do nothing, action throttled
} else {
set.add(id)
yield call(saga, action)
}
}
}
We can emulate an expirable set with redux-saga, and get a purely redux-saga solution.
The code:
function* throttlePerKey(pattern, selector, timeout, saga) {
const set = new Set()
while(true) {
const action = yield take(pattern)
const id = selector(action)
const throttled = set.has(id)
if (throttled) {
// Do nothing, action throttled
} else {
set.add(id)
// Expire items after timeout
yield fork(function* () {
yield delay(timeout)
set.delete(id)
})
yield call(saga, action)
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With