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(/\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
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.js modules are loaded synchronously.
You can deal with this exporting the Promise value.
and:
Modules in Node that you load with
require()
are loaded synchronously and it is not possible forrequire
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:It would not be possible to write:
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:
and changing:
to:
In that case, every other module that uses this module as:
will have
x.GEM_HOME
originally set tonull
but it would eventually get changed to a correct value some time later. It would not be available right away though, becauserequire()
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:
See also this answer for more details: