Channels

Redux-Saga 中的 Channel 通常用于对 Action 进行排序和与外部事件源进行通信。

使用 actionChannel(pattern) 可以创建一个容纳匹配 pattern 的 Action 的队列。这个队列可以缓存所有未执行的 Action。以下是一个缓存所有 Action 并按照顺序处理的示例。

function* watchRequest() {
  // 创建一个队列
  const requestQueue = yield actionChannel('RQUEST');
  while (true) {
    // 从队列中取出一个 Action
    const { payload } = yield take(requestQueue);
    // 调用 Action 对应的处理方法,并阻塞当前 Saga
    yield call(handleRequest, payload);
  }
}

默认情况下 actionChannel 会无限制的缓存所有传入的 Action,但是可以通过提供第二个参数来为 Channel 指定一个缓存。Redux-Sage 提供了以下这些内置的缓存实现可供使用。

  • buffers.none(),不缓存,未被处理的 Action 将会被丢弃。
  • buffers.fixed(limit),容量为 limit 的缓存,溢出时将会报错。
  • buffers.expanding(initialSize),与 fixed 相似,但溢出时会动态扩展。
  • buffers.dropping(limit),容量为 limit 的缓存,溢出时会丢弃最新的 Action。
  • buffers.sliding(limit),容量为 limit 的缓存,溢出时会丢弃最古老的 Action。

与 actionChannel 类似,eventChannel 可以为外来事件源创建一个 Channel。eventChannel 接受一个函数作为参数,即 subscriber ,其主要任务是初始化外部事件来源,eventChannel 会为 subscriber 提供一个 emitter 来将事件源传入的所有事件路由到 Channel。以下示例创建了一个可以倒数计数的 Channel。

function* countdown(secs) {
  return eventChannel(emitter => {
    const interval = setInterval(() => {
      secs -= 1;
      if (secs > 0) {
        emitter(secs);
      } else {
        // 发送 END 将导致 Channel 关闭。
        emitter(END);
      }
    }, 1000);
    // 回传一个 unsubscribe 函数。
    return () => {
      clearInterval(interval);
    };
  });
}

除此之外,还可以通过创建一个独立的 Channel 来在不同的 Saga 之间进行通信。Channel 可以使用 put 手动推送,还可以通过 take 手动取出,并以此来完成 Saga 之间的通信。