商店之间的循环模块依赖关系

Posted

技术标签:

【中文标题】商店之间的循环模块依赖关系【英文标题】:Circular module dependencies between stores 【发布时间】:2016-09-24 08:17:53 【问题描述】:

在我跟踪乐器练习的 React Native 应用中,我有三个商店:

会话存储 目标商店 乐器商店

每个商店管理一个模型(会话、目标、仪器)并通过 REST api 获取/更新服务器。

SessionStore 监听有关 Session 的操作(显然):session.add、session.update。但它也会监听其他存储的更改,以便能够在目标或仪器更改名称时更新会话。

相应地,InstrumentStore 会侦听 Instrument 操作,但也会侦听 Session 操作以更新有关有多少会话使用特定工具的统计信息。

为了能够不存在竞争条件,InstrumentStore 将对 action session.add 进行操作,但首先等待 SessionStore 处理该操作(以确保 Session 已在 API 中更新)。为此,我使用 dispatcher.waitFor 和 SessionStore dispatchToken 作为信号量。

问题:由于所有商店都使用彼此的 dispatchToken,它们都必须相互导入。这是对模块的循环依赖,会导致奇怪的竞争条件。有时,其中一家商店在被其他商店之一包含时尚未构建。

这是我的商店:https://github.com/osirisguitar/GuitarJournalApp/tree/feature/flat-ui/js/stores

我是否以错误的方式使用通量模式?

加法

这就是我想要发生的事情(按顺序):

会话已更新:

    将更新后的会话发送到 API 刷新 SessionStore 刷新目标商店 刷新 InstrumentStore

2、3 和 4 需要等待 1 完成,这就是为什么 GoalStore 和 InstrumentStore 需要 SessionStore 调度令牌。

目标是更新:

    将更新后的目标发送到 API 刷新目标商店 刷新 SessionStore

2和3需要等待1,所以SessionStore需要引入循环依赖的GoalStore dispatchToken。

【问题讨论】:

【参考方案1】:

你有一些重复。

所有商店都会听到所有的派送信息。这就是拥有一个调度员的美妙之处。因此,当您发送 sessions.addsessions.update 操作时,您将访问三个不同的 Store,其中两个正在执行完全相同的操作。这是不行的。

通常,每个 Store 的调度令牌应该只负责更新 那个 商店。因此,您的目标和工具商店应该更新 SessionsStore。 .refresh.emit 应该只在 SessionsStore 调度令牌中发生。


编辑以回答您编辑的问题。

我认为你的困惑是因为你没有认识到 dispatcher.register 接受一个 函数 作为它的参数,而不是一个对象。

在 JS 中,函数不会在声明时评估它们的内容。它们仅在执行时进行评估。

简单示例;

func = function() console.log(testVar)  // No error, even though testVar is undefined
func() // ERROR: testVar is undefined
var testVar = 'hey';
func() // log: 'hey';

dispatcher.register 接受一个函数作为输入,并返回一个键(格式为ID_#)。该键是由调度程序自己生成的,没有运行输入函数。输入函数只是存储起来供以后使用,并在每次调度有效负载时运行。

这意味着您不需要在第一次分派之前定义内部变量。而且因为您不想在创建商店之前发送任何东西,所以这不是问题。

但这也意味着调度程序,默认情况下,对自身有一种循环依赖(依赖于它自己的函数的返回值,存储在外部变量中)。但这就是调度程序的设计。除非您要编写新的调度程序,否则这只是交易的一部分。

还值得指出的是,如果您通过调用多个彼此死锁的waitFors 创建一个真正的循环依赖项,调度程序将正确地抛出一个错误,说明同样多;

Dispatcher.waitFor(...): Circular dependency detected while waiting for ID_#

【讨论】:

你是对的,GoalStore 不应该说 SessionStore.refresh()(和 emitchange),它应该说 GoalStore.refresh()。但我仍然需要 SessionStore dispatchToken 才能等待 SessionStore 在 GoalStore 刷新之前完成其更新......我将使用流程更新原始问题以使其更清晰。 是的,这是非常正确的——那里有一个菜鸟 javascript 错误(没有意识到我正在分配一个函数)。我认为在调度中使用 getDispatchToken() 而不是在声明时尝试获取它会解决它 - 谢谢! 实际上,我收回了这一点。 dispatcher.register 确实返回 dispatchToken (facebook.github.io/flux/docs/dispatcher.html)。所以我所做的是实现我自己的 getDispatchToken 而不是使用来自flux utils的那个。无论如何,谢谢你让我走上正确的道路:-) 哦,对不起,如果我的回答令人困惑!我使用术语“密钥”而不是“调度令牌”。但无论如何,很高兴你把它整理出来。 NP,再次感谢! (我意识到我的问题也有点令人困惑,但是实现了它的工作目标!:-))

以上是关于商店之间的循环模块依赖关系的主要内容,如果未能解决你的问题,请参考以下文章

如何正确处理 Python 中的循环模块依赖关系?

如何解决多模块项目中模块之间的依赖关系?

Terraform - 模块之间的依赖关系

Oracle:如何循环并查找表之间的依赖/依赖关系,以便为每个表执行插入/更新操作?

模块之间的Python依赖关系[重复]

解决 AWS CDK CloudFormation 堆栈之间的循环依赖关系