启动rootSaga的惯用方法是什么?

sla*_*din 35 redux-saga

redux-saga项目已经存在很长时间了,但是这个库仍然有很多令人困惑的事情.其中一个是:如何开始你的rootSaga.例如,在初学者教程中, rootSaga是通过一系列传奇来启动的.像这样

export default function* rootSaga() {
  yield [
    helloSaga(),
    watchIncrementAsync()
  ]
}
Run Code Online (Sandbox Code Playgroud)

然而,在使用传奇助手部分,rootSaga由两个分叉的传奇组成.像这样:

export default function* rootSaga() {
  yield fork(watchFetchUsers)
  yield fork(watchCreateUser)
}
Run Code Online (Sandbox Code Playgroud)

在redux-saga repo中的异步示例中使用了与启动rootSaga相同的方法.但是,如果你查看真实世界和购物卡的例子,你会看到rootSagas那里有一系列分叉的传奇.像这样:

export default function* root() {
  yield [
    fork(getAllProducts),
    fork(watchGetProducts),
    fork(watchCheckout)
  ]
}
Run Code Online (Sandbox Code Playgroud)

另外,如果您在redux-saga问题中阅读了一些讨论,您会看到有些人建议使用spawn而不是fork来为rootSaga保护应用程序完全崩溃,如果您的某个分叉传奇由于某些未处理的异常而被取消.

那么,哪种方式是启动rootSaga的最正确的方法?现有的有什么区别?

Seb*_*ber 14

你可以开始多根传奇.但是任何传奇都有能力自己创造另一个传奇.因此,有可能开始一个单根传奇,创造另一个传奇.

您只需要知道错误如何传播到父级传奇.如果你有一个根传奇和一个子传奇崩溃,默认情况下,错误将传播到将终止的父级,这也将杀死从这个父级启动的所有其他传奇.

由您来决定这种行为.根据您的应用程序,你可能希望有一个快速失败行为(使整个应用程序无法使用,如果有这样的问题),或故障安全,并尽量使应用程序继续工作,即使如果某些部分可能有问题.

一般来说,我建议您启动多个根传奇,或者您的父传奇使用spawn而不是fork使您的应用程序在发生崩溃时仍然可用.请注意,在某些地方忘记捕获错误也很容易.例如,如果单个API请求失败,您通常不希望所有应用都变得无法使用

编辑:我建议你看看https://github.com/yelouafi/redux-saga/issues/570

在这个redux-saga问题中,我展示了启动传奇的不同方法及其对您的应用程序的影响.

TLDR:这就是我通常开始根源传奇的方式:

const makeRestartable = (saga) => {
  return function* () {
    yield spawn(function* () {
      while (true) {
        try {
          yield call(saga);
          console.error("unexpected root saga termination. The root sagas are supposed to be sagas that live during the whole app lifetime!",saga);
        } catch (e) {
          console.error("Saga error, the saga will be restarted",e);
        }
        yield delay(1000); // Workaround to avoid infinite error loops
      }
    })
  };
};

const rootSagas = [
  domain1saga,
  domain2saga,
  domain3saga,
].map(makeRestartable);

export default function* root() {
  yield rootSagas.map(saga => call(saga));
}
Run Code Online (Sandbox Code Playgroud)


np8*_*np8 14

如何创建rootSaga?

据的终极版,佐贺芯显影剂[1 ,2]以创建rootSaga惯用的方法是使用在所有效应Combinator的.此外,请注意,不推荐使用来自sagas的数组.

例1

你可以使用像这样(+全)

import { fork, all } from 'redux-saga/effects';
import firstSaga from './firstSaga';
import secondSaga from './secondSaga';
import thirdSaga from './thirdSaga';

export default function* rootSaga() {
    yield all([
        fork(firstSaga),
        fork(secondSaga),
        fork(thirdSaga),
    ]);
}
Run Code Online (Sandbox Code Playgroud)

例2

取自这里

// foo.js
import { takeEvery } from 'redux-saga/effects';
export const fooSagas = [
  takeEvery("FOO_A", fooASaga),
  takeEvery("FOO_B", fooBSaga),
]

// bar.js
import { takeEvery } from 'redux-saga/effects';
export const barSagas = [
  takeEvery("BAR_A", barASaga),
  takeEvery("BAR_B", barBSaga),
];

// index.js
import { fooSagas } from './foo';
import { barSagas } from './bar';

export default function* rootSaga() {
  yield all([
    ...fooSagas,
    ...barSagas
  ])
}
Run Code Online (Sandbox Code Playgroud)

fork与spawn

forkspawn都将返回Task对象.分叉任务附加到父级,而生成的任务与父级分离.

  • 叉子中的错误处理[ link ]:

    子任务的错误会自动冒泡到父母身上.如果任何分叉的任务引发了未被捕获的错误,那么父任务将以 子Error中止,并且整个Parent的执行树 (即分叉任务+父项主体表示的主要任务,如果它仍在运行)将被取消.

  • 生成任务中的错误处理[ link ]:

    在返回之前,父级不会等待分离的任务终止,并且可能影响父级或分离的任务的所有事件都是完全独立的(错误,取消).

基于上面,您可以使用fork来执行"关键任务"任务, "如果此任务失败,请崩溃整个应用程序",并为"非关键"任务生成, "如果此任务失败,请不要传播父母的错误".