使用redux-saga处理大量事件的订阅/取消订阅

时间:2017-04-25 07:09:48

标签: javascript reactjs redux redux-saga saga

在我目前的项目中,我正在处理firebase websocket订阅。不同的组件可以订阅不同的数据,例如在项目列表中,每个ListItem组件通过在SUBSCRIBE中分派componentDidMount操作订阅该特定项目的websocket“事件”,并通过调度UNSUBSCRIBE操作取消订阅componentWillUnmount

我的传奇看起来像这样:

const subscriptions = {}

export function * subscribeLoop () {
  while (true) {
    const { path } = yield take(SUBSCRIBE)
    subscriptions[path] = yield fork(subscription, path)
  }
}

export function * unsubscribeLoop () {
  while (true) {
    const { path } = yield take(UNSUBSCRIBE)
    yield cancel(subscriptions[path])
  }
}

export function * subscription (path) {
  let ref

  try {
    const updateChannel = channel()

    ref = api.child(path)
    ref.on('value', snapshot => {
      updateChannel.put(snapshot.val())
    })

    while (true) {
      const data = yield take(updateChannel)
      yield put(handleUpdate(path, data))
    }
  } finally {
    if (yield cancelled()) {
      ref.off()
      ref = null
    }
  }
}

我认为这不是解决这个问题的正确方法 - 在500件物品清单上确实相当慢。

如何优化效果?

  • 我甚至需要分叉吗?
  • 我应该引入某种延迟来给线程一些空间来处理其他事情吗?

任何提示都表示赞赏。

1 个答案:

答案 0 :(得分:1)

  

我应该引入某种延迟来给线程一些空间>处理其他事情?

首先,有必要记住使用redux saga和fork之类的效果实际上并没有创建任何在无限循环中扭曲的线程。它只是组合一系列回调的语法糖,因为yield运算符提供了双方传递的对象。从这个角度来看,强制延迟的问题没有意义 - 因为线程并不存在。

  

我甚至需要分叉吗?

在适当技能的情况下,通常可以在没有一组调用的情况下执行,并且可以在一个根传奇中执行所有操作。我们的想法是在websocket的当前词汇区域中使用回调函数进行订阅,并期望在延迟承诺的基础上在伪无限循环中获取消息。

从概念上讲,代码看起来大致如此:

const subscribers = new Map()

function * webSocketLoop() {
  let resolver = null
  let promise = new Promise(resolve => (resolver = resolve))
  let message = null;

  websocket.on('message', (payload) => {
    message = Object.assign({}, payload)
    resolver()
    promise = promise.then(() => new Promise(resolve => (resolver = resolve)))
  })

  while(true) {
    yield call(() => promise)
    const type = message.type
    const handlers = subscribers.get(type) || []
    handlers.forEach(func => func(message))
  }
}

export function * mainSaga () {
  yield takeEvery(SUBSCRIBE, subscribe)
  yield takeEvery(UNSUBSCRIBE, unsubscribe)
  yield fork(webSocketLoop)
}