while true 在 redux sage 中是否仅适用于长轮询或其他用例?

Is while true in a redux sage only for long polling or for other use cases?

我通常会猜测 redux-saga while(true) 将用于长轮询,我看到其他关于长轮询的帖子。但是,我加入了一个项目,我看到大约 44 个带有 while(true) 的 sagas,这似乎意味着没有办法对这个项目进行长轮询(我猜一个典型的项目将是 1 或最多 2 个长轮询来收集一次拍摄所有信息)。这是一个例子...

 function* enrollAddContactSaga() {
  while (true) {
    const { username, appName } = yield take(ENROLL_ADD_CONTACT);
    const newUserId = uuidv4();
    yield put(enrolllNewContact(newUserId, username));
    const { contactAddSuccess, contactAddFailure } = yield race({
      contactAddSuccess: take(ENROLL_NEW_CONTACT_ADD_SUCCESS),
      contactAddFailure: take(ENROLL_NEW_CONTACT_ADD_FAILURE),
    });
    if (contactAddSuccess) {
      yield put(enrollCheckCredentialStatus({ username, appName }));
    } else {
      yield put(
        showAlert('Oops!', buildErrorMessage(contactAddFailure), 'error'),
      );
    }
  }
}

有人可以解释一下吗? while(true) 有什么用?

我真的认为框架会不断调用它,唯一会中断的是在远程调用期间,一旦 returns,传奇 returns,因为它永远不会完成后,它会再次调用该方法。

注意:我也没有在生成器 saga 函数中看到任何 return 语句来使它完成。

基本上,如果您希望在应用程序的生命周期内(或直到被父传奇取消)运行 的传奇,没有 breakwhile(true) 很有用。通常这是因为这个 saga 负责监听一些事件,而这些事件永远不会停止相关。

在您的特定代码中,传奇进入循环,然后立即 yields 直到 ENROLL_ADD_CONTACT 动作发生。 saga 不需要为此进行轮询,redux saga 将检查任何已分派的操作,并在必要时唤醒您的 saga。如果该动作从未发生,那么您的 saga 将永远暂停。假设该操作确实发生了,您的 saga 将在那时恢复执行。

作为 saga 运行 的其余部分,它将执行其他一些异步操作,在此期间它不会监听更多 ENROLL_ADD_CONTACT 操作。所以假设,如果其中一个动作发生在这段时间内,它将被忽略。最终,到达循环的末尾并循环回到顶部,此时它再次开始侦听动作。

换句话说,您展示的代码实现了与 takeLeading 非常相似的东西,只是在一个 saga 中,而不是分成两个。因此可以像这样实现类似的行为:

function* enrollAddContactSaga() {
  yield takeLeading(ENROLL_ADD_CONTACT, someOtherSaga);
}

function* someOtherSaga(action) {
  const { username, appName } = action;
  const newUserId = uuidv4();
  yield put(enrolllNewContact(newUserId, username));
  const { contactAddSuccess, contactAddFailure } = yield race({
    contactAddSuccess: take(ENROLL_NEW_CONTACT_ADD_SUCCESS),
    contactAddFailure: take(ENROLL_NEW_CONTACT_ADD_FAILURE),
  });
  if (contactAddSuccess) {
    yield put(enrollCheckCredentialStatus({ username, appName }));
  } else {
    yield put(
      showAlert('Oops!', buildErrorMessage(contactAddFailure), 'error'),
    );
  }
}