从Promise结果导出节点module

IT技术 javascript node.js coffeescript
2021-03-16 02:32:25

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

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

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

2个回答

您加载的 Node 中的modulerequire()是同步加载的,并且不可能require返回任何异步加载的值。它可以返回一个Promise,但该module的用户必须将其用作:

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内部解析 promise,并通过添加如下内容使其在导出的对象上设置属性:

module.exports = { GEM_HOME: null };

并改变:

module.exports = GEM_HOME

到:

module.exports.GEM_HOME = GEM_HOME

在这种情况下,使用此module的每个其他module:

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

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

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

另请参阅此答案以获取更多详细信息:

x.GEM_HOME 始终未定义。似乎导出了对象的副本。
2021-05-04 02:32:25
很好的答案,尽管令人失望。我最终发现在我的特定情况下,我可以使用child_process.execSync,这解决了我的问题,但没有解决异步要求的真正问题。
2021-05-09 02:32:25

Node.js module是同步加载的

您可以通过导出 Promise 值来处理此问题。

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

和:

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

mod.then((value => ...);
当然,但在第二个块中 - 这意味着如果我的导出module依赖于该值,它也必须异步完成,下一个也是如此,下一个......这就是我试图避免的
2021-05-14 02:32:25