javascript - 使用 Node.js require 和 CoffeeScript 中的类解决循环依赖

标签 javascript node.js coffeescript require circular-dependency

我想知道在使用 CoffeeScript 类和 super 时,是否有一种方法可以惯用地避免 Node.js 的 require 的循环依赖问题。给定以下简化的 CoffeeScript 文件:

a.咖啡:

C = require './c'
B = require './b'

class A extends C
    b: B

    someMethod: ->
        super

module.exports = A

b.咖啡:

C = require './c'
A = require './a'

class B extends C
    a: A

    someMethod: ->
        super

module.exports = B

这里第一个明显的问题是 A 和 B 之间存在循环依赖关系。无论哪个先求值,都会将 {} 作为对另一个的引用。为了在一般情况下解决这个问题,我可能会尝试对每个做这样的事情:

a.咖啡:

C = require './c'

class A extends C

module.exports = A

B = require './b'
_ = require 'underscore'

_.extend A::,
    b: B

    someMethod: ->
        super

这有点 hack,但似乎是通过将 module.exports 移动到依赖项 B 的 require 之前解决循环依赖项的一种常见方法。自 CoffeeScript classes can't be reopened ,然后它使用某种形式的 extend 调用(这可以是复制属性和方法的任何方式)到 A.prototype(又名 A::) 完成类(class)。现在的问题是 super 只能在类声明的上下文中正常工作,所以这段代码无法编译。我正在寻找一种方法来保留 super 和其他 CoffeScript 类功能。

最佳答案

有几种规范的方法可以处理这个问题。在我看来,它们都不是特别优秀。 ( Node 真的需要支持实际替换原始上下文中的临时对象,在循环情况下。这样做的好处是值得做一些丑陋的,hacky V8诡计,IMO。/rant )

后期 build

你可以有一个“更高级别”的模块,也许是你的库的入口模块,执行相互依赖的事物的最终设置:

# <a.coffee>
module.exports =
class A extends require './c'

    someMethod: ->
        super

# <b.coffee>
module.exports =
class B extends require './c'

    someMethod: ->
        super

# <my_library.coffee>
A = require './a'
B = require './b'

A.b = new B
B.a = new A

module.exports = A: A, B: B

可怕的原因是:您现在已经将关注点合并到更高级别的模块中,并从它有意义的上下文中删除了该设置代码(并且希望在其中保持维护。 ) 观看事物不同步的好方法。

依赖注入(inject)

我们可以通过将设置移回每个单独的子模块的关注点来改进上述内容,并且只将依赖管理移除到更高级别的文件中。依赖项将由更高级别的模块获取(没有循环),然后根据需要传递:

# <a.coffee>
module.exports = ({B})-> ->
    # Each module, in addition to being wrapped in a closure-producing
    # function to allow us to close over the dependencies, is further
    # wrapped in a function that allows us to defer *construction*.
    B = B()

    class A extends require './c'
        b: new B

        someMethod: ->
            super

# <b.coffee>
module.exports = ({A})-> ->
    # Each module, in addition to being wrapped in a closure-producing
    # function to allow us to close over the dependencies, is further
    # wrapped in a function that allows us to defer *construction*.
    A = A()

    class B extends require './c'
        a: new A

        someMethod: ->
            super

# <my_library.coffee>
A = require './a'
B = require './b'

# First we close each library over its dependencies,
A = A(B)
B = B(A)

# Now we construct a copy of each (which each will then construct its own
# copy of its counterpart)
module.exports = A: A(), B: B()

# Consumers now get a constructed, final, 'normal' copy of each class.

可怕是因为:好吧,除了在这个特定场景中它绝对丑陋之外(!!?!),你刚刚将解决依赖性问题问题推到了“堆栈”给消费者。在这种情况下,那个消费者仍然是你自己,这很好......但是现在,当你想通过 require 公开 A alone 时会发生什么('my_library/a')?现在您必须向消费者证明他们必须使用 X、Y 和 Z 依赖项来参数化您的子模块……等等等等。在兔子洞里。

未完成类(class)

因此,为了迭代上述内容,我们可以通过直接在类上实现它来从消费者那里抽象出一些依赖困惑(从而也将关注点保持在本地):

# <a.coffee>
module.exports =
class A extends require './c'

    @finish = ->
        require './b'
        @::b = new B

    someMethod: ->
        super

# <b.coffee>
module.exports =
class B extends require './c'

    @finish = ->
        require './a'
        @::a = new A

    someMethod: ->
        super

# <my_library.coffee>
A = require './a'
B = require './b'

module.exports = A: A.finish(), B: B.finish()

可怕是因为:不幸的是,这仍然会给您的 API 添加一些概念上的开销:“确保在使用 A 之前总是调用 A.finish() !”您的用户可能不会接受。同样,它可能会导致子模块之间的模糊、难以维护的错误依赖关系:现在,A 可以使用 B 的元素......除了 B 的部分依赖于 A。(以及哪些部分这些是,在开发过程中可能仍然不明显。)

解决循环依赖

我无法为您编写这部分内容,但这是唯一不可怕的解决方案;如果您向他们提出这个问题,这是任何 Node 程序员都会向您提出的规范问题。我本着 Stack Overflow 的精神提供了以上内容,假设您知道自己在做什么(并且有非常好的理由拥有循环依赖性,并且删除它们将是非常重要的,而且更多对你的项目的危害比上面列出的任何缺点都多)......但在所有现实中,最可能的情况是你只需要重新设计你的架构以避免循环依赖。 (是的,我知道这个建议很糟糕。)

祝你好运! (=

关于javascript - 使用 Node.js require 和 CoffeeScript 中的类解决循环依赖,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24523325/

相关文章:

node.js - 在 NodeJS 中观察流式 HTTP 响应进度,express

coffeescript - 使用 extras/coffee-script.js 在浏览器中编译 CoffeeScript

node.js - 在 JS 应用程序文件中找不到 Require Express 的意外字符串错误

javascript - JavaScript 中对象/数组的性能如何? (专门针对 Google V8)

javascript - Express、Jade 和 NodeJS : Navigate between pages

javascript - JS ES6 模板文字和数字的前导/后缀零

node.js - 将 Selenium 的 findElements 中的 Promise 数组转换为对象数组

node.js - Node.js 中子进程之间的通信

javascript - Onclick 不适用于支持

javascript - 如何创建显示目录 HTML5 Javascript 中所有文件的下拉菜单