从诺言结果导出节点模块

我试图重写一个模块来返回一个不同的值,但现在它使用asynchronous调用来获得该值。 (如果有child_process则使用child_process )。 我把它包装在一个Promise中,但这对我来说并不重要 – 它可以在原来的child_processcallback中,但问题是我无法将应用程序连接到应用程序的任何地方,因为我需要这个同步。 这是我的模块:

 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将是asynchronous的,并且这个链将继续。 我如何避免这种模式?

使用require()加载的Node中的模块将同步加载,并且require不可能返回asynchronous加载的任何值。 它可以返回一个承诺,但该模块的用户将不得不使用它:

 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 

当然,你可以在你的模块内部parsingpromise,并通过添加如下内容来设置导出对象的属性:

 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()在promise被解决并且值被设置之前返回。

有一个正在进行的讨论,引入asynchronous模块加载与不同的语法和语义,可能适合您的使用情况。 这是一个有争议的话题,值得一读的是它背后的基本原理 – 请参阅:

  • Node.js,TC-39,以及来自iBM的James M Snell的模块
  • ES6模块互操作性 – Node.js增强build议
  • 在.js的防御中 – Dave Herman,Yehuda Katz和CaridyPatiño提出的关于Node.js模块的build议
  • 讨论节点-eps (002:ES6模块互操作)的合并请求#3

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

  • 为什么有同步和asynchronous模块的规范?

Node.js模块同步加载。

你可以处理这个输出Promise值。

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

和:

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