【问题标题】:redux saga, throttle/debounce conditionally?redux saga,有条件地节流/去抖动?
【发布时间】:2018-10-15 11:16:58
【问题描述】:

我正在记录屏幕上可见的横幅展示次数。

当用户滚动时,同一个横幅可以在短时间内多次显示。

我想防止这种情况发生。

乍一看,throttle 是防止它的完美方法。

但是当您在一页中有多个横幅时,throttle 将不会在屏幕上记录第二个横幅。

那么我怎样才能对每个键进行节流呢? (此示例中,横幅 id 作为键) 即,我想限制每个banner_id 的横幅展示次数。 (这就像服务器限制每个 api 密钥的 api_endpoint 访问)

编辑

可以考虑为每个键创建throttle,但想知道它是否会占用太多资源?

我想知道 Django-rest-framework 等 API 库如何实现每个 api 键的节流。我想这可能与 saga 油门完全不同。

【问题讨论】:

    标签: redux-saga


    【解决方案1】:

    使用过期地图

    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)
        }
      }
    }
    

    【讨论】:

    • 感谢您的建议,我是 saga 的新手,但是为每个键创建一个通道可能会消耗计算资源?
    • @eugene channel 似乎是 implemented 作为发布者,take() 是订阅者。不应该消耗太多内存。
    • 不过,我明天会重新讨论这个问题。至少,当 5001 毫秒内没有横幅展示时,应该销毁频道。以及完全没有传奇功能的节流的好主意。
    • @eugene 我添加了关于如何在没有redux-saga 的情况下限制每个键的基本想法。
    • 太棒了,有道理,我想可以将最后一次插入时间保存为地图的值并测试键是否不存在或值是否比当前时间早 5000+ 毫秒。
    【解决方案2】:

    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)
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2021-01-03
      • 1970-01-01
      • 2015-07-25
      • 2019-11-11
      • 1970-01-01
      • 2012-07-13
      • 1970-01-01
      • 2021-07-09
      • 2018-02-16
      相关资源
      最近更新 更多