从 Promise 结果中导出 Node 模块
我正在尝试重写一个模块以返回与以前不同的值,但现在它使用异步调用来获取该值.(如果重要,请使用 child_process
).我已经将它包装在一个 Promise 中,但这对我来说并不重要——它可以在原始的 child_process 回调中,但问题是我无法将 Promise 链接到应用程序中的任何地方,因为我需要它变得同步.这是我的模块:
I'm trying to rewrite a module to return a different value than before, but now it uses an async call to get that value. (with child_process
if it matters). I've wrapped it in a Promise, but that's not critical to me - it can be in the original child_process callback, but the problem is I can't chain the promise to everywhere in the app because I need this to become synchronous. Here's my 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(/?
/)
.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
将是异步的,并且该链将继续进行.我该如何避免这种模式?
Clearly, when requiring the module, this doesn't work - and if I return the promise itself, and use then
after require
- my next module.exports
will be async, and this chain will carry on. How do I avoid this pattern?
推荐答案
Node 中使用 require()
加载的模块是同步加载的,require
返回任何异步加载的值.它可以返回一个承诺,但该模块的用户必须将其用作:
Modules in Node that you load with require()
are loaded synchronously and it is not possible for require
to return any value that is loaded asynchronously. It can return a promise but then users of that module would have to use it as:
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
当然,你可以在你的模块中解析承诺,并通过添加如下内容使其在导出的对象上设置一个属性:
Of course you can have the promise resolved inside of your module and make it set a property on the exported object by adding something like this:
module.exports = { GEM_HOME: null };
和变化:
module.exports = GEM_HOME
到:
module.exports.GEM_HOME = GEM_HOME
在这种情况下,使用此模块的所有其他模块:
In that case, every other module that uses this module as:
var x = require('module-name');
将 x.GEM_HOME
最初设置为 null
但它最终会在一段时间后更改为正确的值.但它不会立即可用,因为 require()
在 promise 确定并设置值之前返回.
will have x.GEM_HOME
originally set to null
but it would eventually get changed to a correct value some time later. It would not be available right away though, because require()
returns before the promise is settled and the value is set.
目前正在进行讨论,以引入可能适合您的用例的不同语法和语义的异步模块加载.这是一个有争议的主题,值得阅读其背后的所有基本原理 - 请参阅:
There is an ongoing discussion to introduce asynchronous module loading with different syntax and semantics that may be suited for your use case. It's a controversial subjects and it's worth reading all of the rationale behind it - see:
- Node.js、TC-39 和模块 来自 IBM 的 James M Snell
- ES6 模块互操作性 - 节点.js 增强建议
- 为.js辩护 -Dave Herman、Yehuda Katz 和 Caridy Patiño 提出的 Node.js 模块提案
- 关于node-eps的Pull Request #3的讨论(002:ES6 模块互操作)
- Node.js, TC-39, and Modules by James M Snell from iBM
- ES6 Module Interoperability - Node.js Enhancement Proposals
- In Defense of .js - A Proposal for Node.js Modules by Dave Herman, Yehuda Katz and Caridy Patiño
- Discussion on the Pull Request #3 of node-eps (002: ES6 module interop)
有关详细信息,另请参阅此答案:
See also this answer for more details:
- javascript - 为什么有同步和异步模块的规范吗?
相关文章