redux 传奇,throttle/debounce 有条件?
redux saga, throttle/debounce conditionally?
我正在记录横幅在屏幕上可见时的展示次数。
当用户滚动时,同一横幅可以在短时间内多次显示。
我想避免这种情况。
乍一看,throttle
是防止它的完美方法。
但是当您在一个页面中有多个横幅时,如果受到限制,throttle
将不会在屏幕上记录第二个横幅。
那么我如何限制每个键? (横幅 id 作为本例中的键)
即,我想限制每个 banner_id 的横幅印象。 (这就像服务器限制每个 api 键的 api_endpoint 访问)
编辑
可以考虑为每个键创建 throttle
,但不知道它是否会占用太多资源?
我想知道 API 库(例如 Django-rest-framework)如何实现每个 api 键的节流。我想这可能与saga throttle的作用完全不同。
使用可过期地图
像 django-rest
这样的东西使用 expirable map 进行节流。一个过期的 set 也足以完成任务。
不幸的是,我不能为过期 map/set 推荐一个确切的 npm 模块。
伪代码:
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)
}
}
}
只使用 redux-saga
我们可以用 redux-saga 模拟过期集,得到一个纯粹的 redux-saga 解决方案。
代码:
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)
}
}
}
Andrey 的 redux-saga 解决方案很棒。我稍微修改了它以包含尾随调用。对于我的用例(多人文档编辑器),我需要它在进行更改后立即发送数据,但也在油门延迟结束时发送数据,以便始终发送最新数据。
function* throttlePerKey(pattern, selector, timeout, saga) {
const map = new Map()
while (true) {
const action = yield take(pattern)
const id = selector(action)
const throttled = map.has(id)
if (throttled) {
// track how many attempts there were
map.set(id, map.get(id) + 1)
} else {
map.set(id, 1)
// Expire items after timeout
yield fork(function* () {
yield delay(timeout)
// Call at the end if there were multiple attempts
if (map.get(id) > 1) {
yield call(saga, action)
}
map.delete(id)
})
// Call immediately on first attempt
yield call(saga, action)
}
}
}
我正在记录横幅在屏幕上可见时的展示次数。
当用户滚动时,同一横幅可以在短时间内多次显示。
我想避免这种情况。
乍一看,throttle
是防止它的完美方法。
但是当您在一个页面中有多个横幅时,如果受到限制,throttle
将不会在屏幕上记录第二个横幅。
那么我如何限制每个键? (横幅 id 作为本例中的键) 即,我想限制每个 banner_id 的横幅印象。 (这就像服务器限制每个 api 键的 api_endpoint 访问)
编辑
可以考虑为每个键创建 throttle
,但不知道它是否会占用太多资源?
我想知道 API 库(例如 Django-rest-framework)如何实现每个 api 键的节流。我想这可能与saga throttle的作用完全不同。
使用可过期地图
像 django-rest
这样的东西使用 expirable map 进行节流。一个过期的 set 也足以完成任务。
不幸的是,我不能为过期 map/set 推荐一个确切的 npm 模块。
伪代码:
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)
}
}
}
只使用 redux-saga
我们可以用 redux-saga 模拟过期集,得到一个纯粹的 redux-saga 解决方案。
代码:
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)
}
}
}
Andrey 的 redux-saga 解决方案很棒。我稍微修改了它以包含尾随调用。对于我的用例(多人文档编辑器),我需要它在进行更改后立即发送数据,但也在油门延迟结束时发送数据,以便始终发送最新数据。
function* throttlePerKey(pattern, selector, timeout, saga) {
const map = new Map()
while (true) {
const action = yield take(pattern)
const id = selector(action)
const throttled = map.has(id)
if (throttled) {
// track how many attempts there were
map.set(id, map.get(id) + 1)
} else {
map.set(id, 1)
// Expire items after timeout
yield fork(function* () {
yield delay(timeout)
// Call at the end if there were multiple attempts
if (map.get(id) > 1) {
yield call(saga, action)
}
map.delete(id)
})
// Call immediately on first attempt
yield call(saga, action)
}
}
}