redux-saga项目已经存在很长时间了,但是这个库仍然有很多令人困惑的事情。其中一个是:如何开始你的rootSaga。例如,在beginner tutorial中,rootSaga是由一系列传奇开始的。喜欢这个
export default function* rootSaga() {
yield [
helloSaga(),
watchIncrementAsync()
]
}
然而,在using saga helpers部分,rootSaga由两个分叉的传奇组成。像这样:
export default function* rootSaga() {
yield fork(watchFetchUsers)
yield fork(watchCreateUser)
}
启动rootSaga的方法与redux-saga repo中的异步示例相同。但是,如果你查看真实世界和购物卡的例子,你会看到rootSagas那里有一系列分叉的传奇。像这样:
export default function* root() {
yield [
fork(getAllProducts),
fork(watchGetProducts),
fork(watchCheckout)
]
}
另外,如果你在redux-saga问题上阅读了一些讨论,你会看到有些人建议使用spawn而不是fork来为rootSaga保护应用程序完全崩溃,如果你的某个分叉传奇被取消了未处理的例外。
那么,哪种方式是启动rootSaga的最正确方法?现有的有什么区别?
答案 0 :(得分:14)
你可以开始多根传奇。但是任何传奇都有能力自己创造另一个传奇。因此,可以创建一个单根传奇,创造另一个传奇。
您只需要了解错误如何传播到父级传奇。如果你有一个单根传奇和一个子传奇崩溃,默认情况下,错误将传播到将终止的父节点,这也将杀死从这个父节点开始的所有其他传奇。
由您来决定这种行为。根据您的应用程序,您可能希望快速失败行为(如果出现此类问题则使整个应用程序无法使用)或安全失败,并尝试使应用程序继续工作,即使某些部分可能存在问题。
一般情况下,我建议您启动多根传奇,或者您的父传奇使用spawn
代替fork
,以便在发生崩溃时您的应用仍可使用。请注意,在某些地方忘记捕获错误也很容易。例如,如果单个API请求失败,您通常不希望所有应用都无法使用
修改:我建议您查看https://github.com/yelouafi/redux-saga/issues/570
在这个redux-saga issue中,我展示了启动传奇的不同方法及其对你的应用程序的影响。
TLDR :这就是我通常启动root sagas的方式:
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));
}
答案 1 :(得分:11)
根据redux-saga [1的核心开发人员,2] 创建rootSaga的惯用方法是使用all Effect Combinator。此外,请注意从sagas is deprecated产生数组。
您可以使用this(+ all)
之类的内容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),
]);
}
// 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
])
}
fork和spawn都会返回Task个对象。分叉任务附加到父级,而衍生任务从父级分离。
分叉[link]中的错误处理:
来自子任务的错误会自动冒充他们的父母。如果 任何分叉的任务都会引发一个未被捕获的错误,然后父任务将 使用子错误和整个父执行树中止 (即分叉任务+父母身体代表的主要任务,如果 它仍然在运行)将被取消。
衍生任务中的错误处理[link]:
父级不会等待分离的任务在返回之前终止,所有可能影响父级的事件或分离的任务完全独立(错误< / em>,取消)。
基于以上所述,您可以使用fork for&#34;任务关键&#34;任务,即&#34;如果此任务失败,请崩溃整个应用程序&#34;,并产生&#34;不重要&#34;任务,即&#34;如果此任务失败,请不要将错误传播给父级&#34;。