跳到主要内容

故障排查

添加 saga 后应用冻结

确保你在生成器函数中 yield 了效果。

考虑以下示例:

import { take } from 'redux-saga/effects'

function* logActions() {
while (true) {
const action = take() // 错误
console.log(action)
}
}

它会将应用程序放入无限循环,因为 take() 只创建效果的描述。除非你为中间件执行 yield,否则 while 循环将像常规 while 循环一样运行,并冻结你的应用程序。

添加 yield 将暂停生成器并将控制权返回给 Redux Saga 中间件,该中间件将执行效果。在 take() 的情况下,Redux Saga 将等待下一个匹配模式的动作,然后才会恢复生成器。

要修复上面的示例,yieldtake() 返回的效果:

import { take } from 'redux-saga/effects'

function* logActions() {
while (true) {
const action = yield take() // 正确
console.log(action)
}
}

我的 Saga 缺少派发的动作

确保 Saga 没有在某些效果上被阻塞。当 Saga 在等待效果解决时,它将无法接收派发的动作,直到效果被解决。

例如,考虑这个例子

function* watchRequestActions() {
while (true) {
const { url, params } = yield take('REQUEST')
yield call(handleRequestAction, url, params) // Saga 将在此处阻塞
}
}

function* handleRequestAction(url, params) {
const response = yield call(someRemoteApi, url, params)
yield put(someAction(response))
}

watchRequestActions 执行 yield call(handleRequestAction, url, params) 时,它将等待 handleRequestAction 结束并返回,然后才继续下一个 yield take。例如,假设我们有这样的事件序列

UI                     watchRequestActions             handleRequestAction
---------------------------------------------------------------------------
.......................take('REQUEST').......................................
dispatch(REQUEST)......call(handleRequestAction).......call(someRemoteApi)... 等待服务器响应
.............................................................................
.............................................................................
dispatch(REQUEST)............................................................ 动作丢失!!
.............................................................................
.............................................................................
.......................................................put(someAction).......
.......................take('REQUEST')....................................... saga 恢复

如上所示,当 Saga 在阻塞调用上被阻塞时,它将错过所有在此期间派发的动作。

为了避免阻塞 Saga,你可以使用 fork 而不是 call 来进行非阻塞调用

function* watchRequestActions() {
while (true) {
const { url, params } = yield take('REQUEST')
yield fork(handleRequestAction, url, params) // Saga 将立即恢复
}
}

错误冒泡到根 saga 的错误堆栈不可读

saga 中的任务本质上是异步的,所以我们必须做一些额外的工作来显示 "saga 堆栈",就像它是一系列同步调用的链。所以从 redux-saga@v1 开始,当错误冒泡到根 saga 时,库会构建那个 "saga 堆栈" 并将其作为 onError 回调的第二个参数的属性 sagaStack: string 传递(也参见 中间件选项),所以你可以将它发送到你的错误跟踪系统或做其他额外的工作。

结果,你可以在控制台中看到类似这样的内容。

saga-error-stack.png

如果你想在开发目的中有那些带有文件名和行号的 "saga 堆栈",你可以添加 babel-plugin,它允许你有增强的信息。 文档可在这里找到。 关于 babel-plugin 使用示例,请查看此示例

添加 babel-plugin-redux-saga 后,相同的输出看起来像

saga-error-stack-with-babel-plugin.png

注意:它也适用于测试,只需确保你(或你的运行器)通过 sagaMiddleware 运行 saga。

saga-error-stack-node.png