跳至主要内容

故障排除

添加 saga 后应用程序冻结

确保从生成器函数中yield效果。

请考虑以下示例

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

function* logActions() {
while (true) {
const action = take() // wrong
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() // correct
console.log(action)
}
}

我的 Saga 丢失了分派的 action

确保 Saga 没有被某些 effect 阻塞。当 Saga 正在等待 Effect 解决时,它将无法接收分派的 action,直到 Effect 解决。

例如,考虑以下示例

function* watchRequestActions() {
while (true) {
const { url, params } = yield take('REQUEST')
yield call(handleRequestAction, url, params) // The Saga will block here
}
}

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)... Wait server resp.
.............................................................................
.............................................................................
dispatch(REQUEST)............................................................ Action missed!!
.............................................................................
.............................................................................
.......................................................put(someAction).......
.......................take('REQUEST')....................................... saga is resumed

如上所示,当 Saga 被 **阻塞调用** 阻塞时,它将错过其间分派的全部 action。

为了避免阻塞 Saga,可以使用 **非阻塞调用**,使用 fork 而不是 call

function* watchRequestActions() {
while (true) {
const { url, params } = yield take('REQUEST')
yield fork(handleRequestAction, url, params) // The Saga will resume immediately
}
}

错误堆栈对于冒泡到根 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