ES6模块和循环依赖
问题描述:
我有在ES6这个问题在通天环境
// A.js
class A {
}
export default new A();
// B.js
import C from './C';
class B {
}
export default new B();
// C.js
import A from './A';
import B from './B';
class C {
constructor(A, B){
this.A = A;
this.B = B; // undefined
}
}
export default new C(A, B)
我导入它们是这样的:
// stores/index.js
import A from './A';
import B from './B';
import C from './C';
export {
A,
B,
C
}
而且从我的应用程序入口点我做的:
import * as stores from './stores';
我(希望)预期执行顺序是A - >乙 - > C,但实际上它是A-> C-> B.
这是由于模块B导入了C,所以C模块在B模块之前被评估。这在C的设置中产生问题,因为在那种情况下,B将是undefined。
我见过类似的question,但我不确定init函数是否是这里最好的解决方案,这似乎有点不合理。
问题:在ES6中解决这种循环依赖关系的最佳做法是什么?它可能适用于不同的环境(Babel,Rollup)?
答
有关ES6中循环依赖关系的最佳实践是什么?
完全避免它们。如果您不能(或不想)完全避免它们,请将涉及的模块仅限于使用具有循环依赖性的函数声明,从不使用导入的值初始化顶级值(常量,变量,类) extends
参考)。
什么可能适用于不同的环境(Babel,Rollup)?
模块解析和初始化的顺序在ES6规范中定义,所以在所有ES6环境中都应该是相同的 - 不管模块如何加载以及如何解析其标识符。
如何解决这种循环依赖设置?
如果你确实有循环依赖X -> Y -> Z -> … -> X -> …
,你需要建立一个起点。假设你想先加载X
,虽然它取决于Y
,所以你需要确保X
从不使用任何导入的值,直到圆圈中的所有模块都完全初始化。所以你打破了X
和Y
之间的圆圈,你需要在Y
处启动导入链 - 它将递归遍历依赖关系,直到它停在X
之间,因为它没有进一步的依赖关系,所以没有被初始化,所以它会是第一个要评估的模块。
,你必须遵循那么规则是总是进口Y
进口其他模块中的任何在圈内之前。如果你甚至有一次不使用这个通用的单一入口点,你的房子会崩溃。
在你的具体的例子,这意味着index.js
将需要使用
import A from './A';
import C from './C'; // entry point to circular dependencies
import B from './B';
…
*预期执行的顺序是A - >乙 - > C * - 为其切入点?如果甚至没有使用C,为什么C在B中导入? – estus
它被使用,这是一个缺少实现细节的例子。我已经更新了添加入口点的问题 – Leonardo
省略的细节在这里改变了一切。不会有循环依赖,因为未使用的导入被跳过。考虑提供http://stackoverflow.com/help/mcve。同样仅仅为单例使用类是反模式。 – estus