【问题标题】:Exporting Node module from promise result从 Promise 结果中导出 Node 模块
【发布时间】:2017-05-07 21:09:27
【问题描述】:

我正在尝试重写一个模块以返回与以前不同的值,但现在它使用异步调用来获取该值。 (如果重要,请使用child_process)。我已经将它包装在 Promise 中,但这对我来说并不重要 - 它可以在原始的 child_process 回调中,但问题是我无法将 Promise 链接到应用程序中的任何地方,因为我需要它变得同步。这是我的模块:

exec = require('child_process').exec

platformHome = process.env[if process.platform is 'win32' then 'USERPROFILE' else 'HOME']

getExecPath = new Promise (resolve, reject) ->
  path = process.env.GEM_HOME

  if path
    resolve(path)
  else
    exec 'gem environment', (err, stdout, stderr) ->
      unless err
        line = stdout.split(/\r?\n/)
                 .find((l) -> ~l.indexOf('EXECUTABLE DIRECTORY'))
        if line
          resolve line[line.indexOf(': ') + 2..]
        else
          reject undefined

GEM_HOME = undefined

getExecPath.then (path) ->
  GEM_HOME = path
.catch ->
  GEM_HOME = "#{platformHome}/.gem/ruby/2.3.0"
.then =>
  module.exports = GEM_HOME // or simply return it

显然,当需要模块时,这不起作用 - 如果我返回承诺本身,并在 require 之后使用 then - 我的下一个 module.exports 将是异步的,并且此链将继续。我该如何避免这种模式?

【问题讨论】:

    标签: javascript node.js coffeescript


    【解决方案1】:

    使用require() 加载的 Node 中的模块是同步加载的,require 不可能返回任何异步加载的值。它可以返回一个承诺,但该模块的用户必须将其用作:

    require('module-name').then(value => {
      // you have your value here
    });
    

    写不出来:

    var value = require('module-name');
    // you cannot have your value here because this line
    // will get evaluated before that value is available
    

    当然,你可以在你的模块中解析承诺,并通过添加如下内容使其在导出的对象上设置一个属性:

    module.exports = { GEM_HOME: null };
    

    和变化:

    module.exports = GEM_HOME
    

    到:

    module.exports.GEM_HOME = GEM_HOME
    

    在这种情况下,使用此模块的所有其他模块:

    var x = require('module-name');
    

    x.GEM_HOME 最初设置为null,但它最终会在一段时间后更改为正确的值。但它不会立即可用,因为require() 在承诺完成并设置值之前返回。

    目前正在进行讨论,以引入可能适合您的用例的不同语法和语义的异步模块加载。这是一个有争议的主题,值得阅读其背后的所有基本原理 - 请参阅:

    有关详细信息,另请参阅此答案:

    【讨论】:

    • 很好的答案,尽管令人失望。我最终发现,在我的具体情况下,我可以使用child_process.execSync,它解决了我的问题,但并没有解决异步需求的真正问题。
    • x.GEM_HOME 始终未定义。似乎导出了对象的副本。
    【解决方案2】:

    Node.js 模块同步加载。

    你可以通过导出 Promise 值来处理这个问题。

    #@ your module.js
    module.exports = new Promise()
    

    和:

    #@ your app.js
    const mod = require('./module');
    
    mod.then((value => ...);
    

    【讨论】:

    • 当然,但是在第二个块中 - 这意味着如果我导出的模块依赖于该值,它也必须异步完成,下一个也是如此,下一个......这就是我我试图避免
    猜你喜欢
    • 2020-05-03
    • 2021-09-22
    • 1970-01-01
    • 2022-08-16
    • 2017-12-31
    • 2021-04-06
    • 2022-10-13
    • 1970-01-01
    • 2018-09-30
    相关资源
    最近更新 更多