I posted this answer, but you are welcome to post an improvement.
See the Node.JS source code.
Module.prototype.require = function(path) { return Module._load(path, this); };
Abridged version of _load
Module._load = function(request, parent, isMain) {
var filename = Module._resolveFilename(request, parent);
if (Module._cache[filename]) return Module._cache[filename].exports;
if (NativeModule.exists(filename)) {
if (filename == 'repl') { // special case, needs the real require.
var replModule = new Module('repl');
replModule._compile(NativeModule.getSource('repl'), 'repl.js');
NativeModule._cache.repl = replModule;
return replModule.exports;
}
return NativeModule.require(filename);
}
var module = new Module(filename, parent);
if (isMain) process.mainModule = module, module.id = '.';
Module._cache[filename] = module;
var hadException = true;
try {
module.load(filename);
hadException = false;
} finally {
if (hadException) delete Module._cache[filename];
}
return module.exports;
};
My version of require.async.js
will be something like
var NativeModule = require('native_module');
var fs = require('fs');
if(!require.async) require.async = function (path, callback) { module.exports(path, this, callback); } // Comment out if you dislike using globals
module.exports = function(request, parent, callback) {
var filename = Module.resolve(request, parent); // This is a Sync function. TODO, change it to an async function with a callback.
if (Module.cache[filename]) callback(Module.cache[filename].exports);
else if (NativeModule.exists(filename)) callback(new Error('What are you thinking?'))
else fs.readFile(filename, 'utf8', function(err, file) {
if (Module.cache[filename]) callback(null, Module.cache[filename].exports); // For the case when there are two calls to require.async at a time.
else if(err) callback(err)
else {
var module = new Module(filename, parent);
try {
module._compile(file);
Module.cache[filename] = module;
} catch(ex) {
callback(err)
}
if(Module.cache[filename]) callback(null, module.exports)
}
}
Caveats
- There is one TODO in the code which is to make the multiple calls to
stat
to be async. The actual reading of the file is regular async, so that is good.
- If you are async loading a module, and that module you are loading is sync loading another module, then you have not fully gone async with your code - have you.
- It uses one private method -
_compile
.