Node.js:在对象未完成初始化时调用方法的解决方法?

时间:2012-02-03 16:05:43

标签: javascript node.js coffeescript

我正在努力升级看起来像这样的库(在coffeescript中为了简洁):

//machine.coffee

exports.Machine = class Machine
  constructor: (config) ->
    /** initialize Machine with config data **/

  getSomething: (callback) ->
    /** do something that depends on config **/
    callback null, something     

并按照您的预期使用:

machine = require 'machine'
config = {knob: "tweak", switch: "fiddle" }

myMachine = machine.createMachine config

myMachine.getSomething (err, something) ->
  /** we now have something **/

但是,现在配置依赖于我必须从另一个站点请求的设置,因此看起来更像是这样,并且Machine已更新为解析并使用来自外部源的数据。因此,像这样访问机器有效:

config = {knob: "tweak", switch: 'http://returns/switch/data' }

/**methods now must wait until Machine is initialized with remote config data **/
machine.createMachine config, (err, machine) ->
  machine.getSomething (err, something) ->
     /** we now have something **/

但问题是这打破了原来的用法:

myMachine = machine.createMachine config

/** remote calls to config not completed yet **/

myMachine.getSomething (err, something) ->
  /** we don't have something because Machine is still initializing **/

我的问题:无论如何要保留原始用例吗? 一种方法可能是在未初始化的类上对方法调用进行排队,直到它完全初始化,但我不确定如何开始这样做。有没有办法排队方法?或者是否有其他更好的方法可以使原始用法的遗留代码仍然有效?

澄清: 我无法控制初始config数据,也无法控制随后何时或将在Machine上调用哪些方法。我确实能够以任何必要的方式修改Machine。

3 个答案:

答案 0 :(得分:1)

您可以将远程呼叫拉出到填充config的功能中。然后,您可以将machine.createMachine configgetSomething调用移动到在config完全填写后调用的回调。

这样,您的machine无需知道任何有关远程来源或如何解析数据的信息。

答案 1 :(得分:1)

我认为你不应再公开Machine构造函数了。相反,您应该公开异步工厂函数:

class Machine # not exported
    # ...

exports.createMachine = (config, cb) ->
    getConfig(config, (err, configData) ->
        if err return cb(err)

        cb(new Machine(configData))
    )

答案 2 :(得分:1)

我不确定我是否已经解决了这个问题。 getSomething()已经是异步的,对吧?所以可能是getSomething()的实现已经延迟并返回执行。

如果,otoh,你没有内部延迟机制,即你以前依赖于另一个库提供的延迟,比如构建器中内置的数据库驱动程序,那么你需要建立自己的延迟机构。

我能想到的最简单的形式,就像我的头脑一样:

exports.Machine = class Machine
  constructor: (config) ->
    @deferred = []
    initialize (err, @magic) => 
      @ready = true
      def[0].apply( @, def[1] ) for def in @deferred

  getSomething: (callback) ->
    if @ready
      @magic.getSomething (err, stuff) -> callback( stuff )
    else
      @deferred.push [@getSomething, arguments]

简而言之:如果你还不能做到,记住你在日志中尝试做什么,然后回来。之后,当你准备好做这些事情的时候,循环通过日志然后回到你原来的位置,去接你离开的地方。