【发布时间】:2016-11-25 00:32:00
【问题描述】:
我正在学习redux saga,但不明白作者的意思:
与redux thunk相反,你不会陷入回调地狱,你可以 轻松测试您的异步流程,让您的操作保持纯净。
任何“回调地狱”和“纯动作”的例子都将不胜感激。
【问题讨论】:
标签: javascript reactjs callback redux react-redux
我正在学习redux saga,但不明白作者的意思:
与redux thunk相反,你不会陷入回调地狱,你可以 轻松测试您的异步流程,让您的操作保持纯净。
任何“回调地狱”和“纯动作”的例子都将不胜感激。
【问题讨论】:
标签: javascript reactjs callback redux react-redux
纯函数是一种函数,当给定相同的参数时,将总是产生相同的结果,并且不会修改任何超出其范围的变量。例如,
function addTwoIntegers(a, b) {
return a + b;
}
如果我们传递 a=2 和 b=3,那么结果将始终为 5。没有其他任何变化。这是一件好事,因为它使测试该功能变得更加容易 - 我们可以肯定地知道它们对于给定的输入对的输出是什么。
例如,将其与从 API 加载数据并将其分配给变量的函数进行对比:
let result;
function AddIntegerToNumberFromServer(a) {
fetch('api/numberGenerator').then(function(res) {
result = a + res.data.number;
});
}
在这种情况下,我们可以多次调用具有相同参数的函数,并不能确定得到相同的结果。这样做的结果是该函数更难测试——我们可能必须创建一个 api 的模拟。我们还必须确定 result 的初始值是多少,才能知道我们的函数是否按计划工作。
您可能知道,回调是我们作为参数传递给另一个函数的函数,因此我们可以推迟执行某些代码,直到第二个函数完成。当我们深入到很多层时,回调地狱就会发生 - 正如 jQuery 上面的人所评论的那样,它似乎邀请了这种风格 - 例如:
$(function() {
$('#element').click(function() {
$(this).fadeOut(function() {
$('#anotherElement').fadeIn();
}
}
}
这里的问题主要是人类对代码的理解和易读性。想象一下,如果这更深入(并不少见)要弄清楚发生了什么以及何时发生会有多困难。
就回调而言,Redux-thunk 远不是最糟糕的违规者,而且可读性因素可以通过使用 Promise 而不是回调来减轻。
【讨论】:
...您的行为保持纯洁...
我最好的猜测是这是一个错误。在the redux-thunk README 中没有不纯的动作创建者,更不用说不纯的动作对象了。也许“不纯行为”指的是一种模式,其中“更高级别”的行为-创建者如makeSandwichesForEverybody 包含多个副作用,因此很难测试。
...最终进入回调地狱...
同样makeSandwichesForEverybody 包含许多嵌套的 Promise,随着异步工作流程变得更加复杂,这些 Promise 可能会变得更难理解。我还不能评论的是,这将在 redux-saga 中实现多少简单/复杂。
function makeSandwichesForEverybody() {
return function (dispatch, getState) {
if (!getState().sandwiches.isShopOpen) {
// You don’t have to return Promises, but it’s a handy convention
// so the caller can always call .then() on async dispatch result.
return Promise.resolve();
}
// We can dispatch both plain object actions and other thunks,
// which lets us compose the asynchronous actions in a single flow.
return dispatch(
makeASandwichWithSecretSauce('My Grandma')
).then(() =>
Promise.all([
dispatch(makeASandwichWithSecretSauce('Me')),
dispatch(makeASandwichWithSecretSauce('My wife'))
])
).then(() =>
dispatch(makeASandwichWithSecretSauce('Our kids'))
).then(() =>
dispatch(getState().myMoney > 42 ?
withdrawMoney(42) :
apologize('Me', 'The Sandwich Shop')
)
);
};
}
顺便说一句,我以函数的形式使用了"impure action creators", which I call dispatchers,它们充当动作创建者、调度者并具有副作用。我发现这是管理异步工作的好模式。然而,它使同构应用程序更难/不可能实现并且不容易测试。
【讨论】: