Reactjs React Redux源函数,确保设置多个侦听器?;
如何理解函数ensureCanMutateNextListenersReactjs React Redux源函数,确保设置多个侦听器?;,reactjs,redux,Reactjs,Redux,如何理解函数ensureCanMutateNextListeners 这是个好问题。在此处致电@gaearon发布从 reduxsubscribe函数的示例实现 let subscriptions = []; const subscribe = function (fn) { if (typeof fn !== 'function') { throw Error('The provided listener must be a function'); }
这是个好问题。在此处致电@gaearon发布从
redux
subscribe函数的示例实现
let subscriptions = [];
const subscribe = function (fn) {
if (typeof fn !== 'function') {
throw Error('The provided listener must be a function');
}
var subscribed = true;
// This line is what we are interested in
subscriptions.push(fn);
return function () {
if (!subscribed) {
return;
}
var index = subscriptions.indexOf(fn);
subscriptions.splice(index, 1);
subscribed = false;
};
};
对于执行的每一次发送
,我们必须通知每一位订户
从博客
现在,您可能希望添加到subscribe函数中的一件事是对subscribers集合进行变异保持。您希望侦听器集合的原因不应在调度运行时更改
继续
因此,这里我们有一个函数ensureCanMutateNextListeners,当调用该函数时,检查两个数组是否是相同的数组引用,如果是,则使用slice克隆currentSubscriptions,以便在修改nextSubscriptions数组(添加或删除侦听器)时它不会影响任何当前正在运行的调度管道。这里的目标是确保调度所使用的侦听器是调度开始时的时间点
这个问题困扰了我很长一段时间,虽然上面的答案和博客文章提供了核心思想,但没有给出具体的例子 我的思考过程是:javaScript是单线程的,任何函数都有运行到完成的行为——所以说
subscribe
必须担心当前是否有分派操作在进行,这是没有意义的。如果我们在函数subscribe
中,那么实际上也不可能在dispatch
中:因为subscribe
的主体中没有任何地方被直接或间接调用dispatch
说到这里,我今天才意识到上述逻辑的一个缺陷,我想在这里分享一下。解释是,当在订阅
中时,调度
将不会运行,但反之则不正确<代码>订阅(和取消订阅
)可能在调度
中运行。这是调度的来源
:
function dispatch(action) {
// ...
const listeners = currentListeners = nextListeners
for (let i = 0; i < listeners.length; i++) {
const listener = listeners[i]
listener()
}
return action
}
现在,当我们发送时会发生什么?假设未使用ensureCanMutateNextListeners
,并且subscribe
实际将侦听器推送到currentListeners
store.dispatch(action);
将在所有侦听器中循环:
for (let i = 0; i < listeners.length; i++) {
const listener = listeners[i]
listener()
}
但是,即使只使用redux
公共api,也可能有其他情况会让某些listener
以意外的方式改变侦听器数组
因此,
ensureCanMutateNextListeners
作为一种通用解决方案引入。在dispatch内部,任何对subscribe
和unsubscribe
的间接调用(只有两个公共函数redux
允许您修改侦听器)都将变异currentListeners的副本,从而产生更可预测的行为。在上面的例子中,通过使用ensureCanMutateNextListeners
,doSubscribe
将添加一个add-self到监听器的副本中,调用时,调度中的循环保持不受影响,并且没有任何问题。今天挖掘redux文档,官方API文档对此做了一些解释:>订阅是在每次dispatch()调用之前进行快照的。如果在调用侦听器时订阅或取消订阅,这将不会对当前正在进行的dispatch()产生任何影响。但是,下一个dispatch()调用(无论是否嵌套)将使用订阅列表的最新快照。Aaron Powell在这里的博客文章:我实际上还有另一个问题:
for (let i = 0; i < listeners.length; i++) {
const listener = listeners[i]
listener()
}
const currentListenersCount = listeners.length;
for (let i = 0; i < currentListenersCount; i++) {
const listener = listeners[i]
listener()
}