我尝试重写模块以返回与以前不同的值,但现在它使用异步调用来获取该值。 (如果重要,请child_process
)。我把它包装在Promise中,但这对我来说并不重要 - 它可以在原始的child_process回调中,但问题是我无法将承诺链接到应用程序的任何地方,因为我需要这个变成同步。这是我的模块:
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
显然,当需要模块时,这不起作用 - 如果我自己返回承诺,并在then
之后使用require
- 我的下一个module.exports
将是异步的,这个连锁店将继续。我该如何避免这种模式?
答案 0 :(得分:14)
使用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
当然,您可以在模块内部解析promise,并通过添加以下内容使其在导出的对象上设置属性:
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()
在保证结算并设置值之前返回。
目前正在讨论引入异步模块加载,其中包含可能适合您的用例的不同语法和语义。这是一个有争议的主题,值得阅读它背后的所有理由 - 见:
有关详细信息,请参阅此答案:
答案 1 :(得分:0)
Node.js模块同步加载。
您可以处理此导出Promise值。
#@ your module.js
module.exports = new Promise()
和
#@ your app.js
const mod = require('./module');
mod.then((value => ...);