错误处理

在这一节中,我们将看到如何在前面的例子中处理故障案例。我们假设远程读取因为某些原因失败了,API 函数 Api.fetch 返回一个被拒绝(rejected)的 Promise。

我们希望通过在 Saga 中发起 PRODUCTS_REQUEST_FAILED action 到 Store 来处理那些错误。

我们可以使用熟悉的 try/catch 语法在 Saga 中捕获错误。

  1. import Api from './path/to/api'
  2. import { call, put } from 'redux-saga/effects'
  3. //...
  4. function* fetchProducts() {
  5. try {
  6. const products = yield call(Api.fetch, '/products')
  7. yield put({ type: 'PRODUCTS_RECEIVED', products })
  8. }
  9. catch(error) {
  10. yield put({ type: 'PRODUCTS_REQUEST_FAILED', error })
  11. }
  12. }

为了测试故障案例,我们将使用 Generator 的 throw 方法。

  1. import { call, put } from 'redux-saga/effects'
  2. import Api from '...'
  3. const iterator = fetchProducts()
  4. // 期望一个 call 指令
  5. assert.deepEqual(
  6. iterator.next().value,
  7. call(Api.fetch, '/products'),
  8. "fetchProducts should yield an Effect call(Api.fetch, './products')"
  9. )
  10. // 创建一个模拟的 error 对象
  11. const error = {}
  12. // 期望一个 dispatch 指令
  13. assert.deepEqual(
  14. iterator.throw(error).value,
  15. put({ type: 'PRODUCTS_REQUEST_FAILED', error }),
  16. "fetchProducts should yield an Effect put({ type: 'PRODUCTS_REQUEST_FAILED', error })"
  17. )

在这个案例中,我们传递一个模拟的 error 对象给 throw,这会引发 Generator 中断当前的执行流并执行捕获区块(catch block)。

当然了,你并不一定得在 try/catch 区块中处理错误,你也可以让你的 API 服务返回一个正常的含有错误标识的值。例如,
你可以捕捉 Promise 的拒绝操作,并将它们映射到一个错误字段对象。

  1. import Api from './path/to/api'
  2. import { take, put } from 'redux-saga/effects'
  3. function fetchProductsApi() {
  4. return Api.fetch('/products')
  5. .then(response => {response})
  6. .catch(error => {error})
  7. }
  8. function* fetchProducts() {
  9. const { response, error } = yield call(fetchProductsApi)
  10. if(response)
  11. yield put({ type: 'PRODUCTS_RECEIVED', products: response })
  12. else
  13. yield put({ type: 'PRODUCTS_REQUEST_FAILED', error })
  14. }