Deep in Redux Saga Middleware

Stephen Cui ... 2019-11-18 19:38:33 Knowledge
  • Redux
  • Saga
About 3 min

# 1. Flow

# 1.1 Register Saga Listeners

  • 注册SagaFn监听函数, 并将其注入到Saga Channel中
  • 利用闭包的方式将ReduxStore注入到SagaFn内

# 1.2 Subscribe Action

  • 支持Action拦截
  • 使用channel监听Action

# 1.3 Run Saga Effect

  • 根据Generator返回类型不同而做不同处理

# 2. Core API

# fork

fork ---> proc ---> Next State ---> promise Non-Block模式,单独开启一个Task去完成任务

# take & takeEvery

Take ---> runTakeEffect ---> cb(input) Block模式,阻塞执行Action任务

TakeEvery ---> Take ---> Fork ---> fsmIterator (opens new window) Non-Block模式,非阻塞执行每一次请求,并返回Iterator迭代器类型

# call

创建一个 Effect 描述信息,用来命令 middleware 以参数 args 调用函数 fn 。 fn: Function - 一个 Generator 函数, 也可以是一个返回 Promise 或任意其它值的普通函数。 args: Array - 传递给 fn 的参数数组。

# put & putResolve

put: 创建一个 Effect 描述信息,用来命令 middleware 向 Store 发起一个 action。 这个 effect 是非阻塞型的,并且所有向下游抛出的错误(例如在 reducer 中),都不会冒泡回到 saga 当中。 putResovle(put.resovle): 类似 put,但 effect 是阻塞型的(如果从 dispatch 返回了 promise,它将会等待其结果),并且会从下游冒泡错误。put的Action是AsyncAction

# all

与 all([...effects]) 相同,但就像 race(effects) 那样,传入的是一个带有 label 的 effect 的字典对象。 effects: Object - 一个 {label: effect, ...} 形式的字典对象

注意事项 当并发运行 Effect 时,middleware 将暂停 Generator,直到以下任一情况发生: 所有 Effect 都成功完成:返回一个包含所有 Effect 结果的数组,并恢复 Generator。 在所有 Effect 完成之前,有一个 Effect 被 reject:在 Generator 中抛出 reject 错误。

# apply(context, fn, [args])

call([context, fn], ...args) 的另一种写法。

# cps(fn, ...args)

创建一个 Effect 描述信息,用来命令 middleware 以 Node 风格的函数(Node style function)的方式调用 fn。

# spawn

与 fork(fn, ...args) 相同,但创建的是 被分离的 任务。被分离的任务与其父级任务保持独立,并像顶级任务般工作。父级任务不会在返回之前等待被分离的任务终止,并且所有可能影响父级或被分离的任务的事件都是完全独立的(错误、取消)。

# select

创建一个 Effect,用来命令 middleware 在当前 Store 的 state 上调用指定的选择器(即返回 selector(getState(), ...args) 的结果)。

# flush

创建一个 Effect,用来命令 middleware 从 channel 中冲除所有被缓存的数据。被冲除的数据会返回至 saga,这样便可以在需要的时候再次被利用。

# delay

返回一个 effect 描述信息,用于阻塞执行 ms 毫秒

# throttle(ms, pattern, saga, ...args)

在发起到 Store 并且匹配 pattern 的一个 action 上派生一个 saga。 它在派生一次任务之后,仍然将新传入的 action 接收到底层的 buffer 中,至多保留(最近的)一个。但与此同时,它在 ms 毫秒内将暂停派生新的任务 —— 这也就是它被命名为节流阀(throttle)的原因。其用途,是在处理任务时,无视给定的时长内新传入的 action。 ms: Number - 在 action 开始处理后,无视新 action 的时长;以毫秒为单位。 pattern: String | Array | Function - 有关更多信息,请参见 take(pattern) 的文档 saga: Function - 一个 Generator 函数 args: Array - 传递给启动任务的参数。throttle 会把当前的 action 追加到参数列表中。(即 action 将是 saga 的最后一个参数)

const throttle = (ms, pattern, task, ...args) => fork(function*() {
  const throttleChannel = yield actionChannel(pattern)

  while (true) {
    const action = yield take(throttleChannel)
    yield fork(task, ...args, action)
    yield delay(ms)
  }
})
1
2
3
4
5
6
7
8
9

# reference

https://www.jianshu.com/p/715eb01f6a5f

Last update: October 10, 2021 09:12
Contributors: Stephen Cui