【问题标题】:Unable to understand non-blocking calls in Redux-Saga无法理解 Redux-Saga 中的非阻塞调用
【发布时间】:2020-08-15 15:03:20
【问题描述】:

我正在尝试理解 redux-saga 文档的 Non-blocking calls 部分并坚持使用以下代码

import { fork, call, take, put } from 'redux-saga/effects'
import Api from '...'

function* authorize(user, password) {
  try {
    const token = yield call(Api.authorize, user, password)
    yield put({type: 'LOGIN_SUCCESS', token})
    yield call(Api.storeItem, {token})
  } catch(error) {
    yield put({type: 'LOGIN_ERROR', error})
  }
}

function* loginFlow() {
  while (true) {
    const {user, password} = yield take('LOGIN_REQUEST')
    yield fork(authorize, user, password)
    yield take(['LOGOUT', 'LOGIN_ERROR'])
    yield call(Api.clearItem, 'token')
  }
}

解释说

如果在用户注销之前授权失败,它将调度一个 LOGIN_ERROR 操作,然后终止。因此 loginFlow 将在 LOGOUT 之前获取 LOGIN_ERROR,然后它将进入另一个 while 迭代并等待下一个 LOGIN_REQUEST 操作。

我无法真正理解语句所以 loginFlow 将在 LOGOUT 之前获取 LOGIN_ERROR 然后它会进入另一个 while 迭代并等待下一个 LOGIN_REQUEST 操作。

谁能解释yield put({type: 'LOGIN_ERROR', error})yield take(['LOGOUT', 'LOGIN_ERROR'])之间的关系?

【问题讨论】:

    标签: javascript reactjs react-native redux redux-saga


    【解决方案1】:

    yield put({type: 'LOGIN_ERROR', error}) - 调度 LOGIN_ERROR 类型的操作。

    yield take(['LOGOUT', 'LOGIN_ERROR']) 暂停生成器函数 (loginFlow) 的执行,直到调度 LOGOUTLOGIN_ERROR 类型的操作。

    【讨论】:

      【解决方案2】:

      简单解释一下:

      • yield put({type: 'LOGIN_ERROR',error}) = 指示存在 LOGIN_ERROR 的调度操作。
      • yield take(['LOGOUT', 'LOGIN_ERROR']) = 等待直到有一个 LOGOUT 或 LOGIN_ERROR 动作被分派,只有在有 LOGOUT 或 LOGIN_ERROR 时才继续执行下一行 yield call(Api.clearItem, 'token')

      【讨论】:

        【解决方案3】:

        非阻塞 是一个同步流,这意味着 Saga 不服从代码块并同时读取父块内的行,这就是为什么它被称为Non-Blocking

        屏蔽 call 意味着 Saga 产生了一个 Effect 并在它继续执行下一个块之前等待上一个块,基本上它被称为 Blocking

        就你而言,你只是误解了 redux-saga 的文档,但它就像this

        import {call, cancel, join, take, put} from "redux-saga/effects"
        
        function* saga() {
          yield take(ACTION)              // Blocking: will wait for the action
          yield call(ApiFn, ...args)      // Blocking: will wait for ApiFn (If ApiFn returns a Promise)
          yield call(otherSaga, ...args)  // Blocking: will wait for otherSaga to terminate
        
          yield put(...)                   // Non-Blocking: will dispatch within internal scheduler
        
          const task = yield fork(otherSaga, ...args)  // Non-blocking: will not wait for otherSaga
          yield cancel(task)                           // Non-blocking: will resume immediately
          // or
          yield join(task)                              // Blocking: will wait for the task to terminate
        }
        

        更多信息请阅读Redux-Saga的文档本身

        【讨论】:

          最近更新 更多