12

I would like to have the ability to load a module that has been changed. I would have to of course unload the module first. Since this is a webserver setup, I am asking if there is a way to load the module in an async fashion, to avoid freezing the webserver for the duration of the read of the updated file.

Awhile back Node.JS removed the require.async function. So, on the latest version of Node.JS, what would be the recommended alternative?

  • Should I read the entire file first, and then use the Module library to parse the file contents. (as opposed to the default functionality of taking a file name to read and parse internally) How?
  • Should I outsource this job to some open-source library? Which one?
  • Should I write my own module handler - my own implementation of requireAsync? (I know how.)

Note: I do not want to do anything more than load a module async, so please do not recommend that I replace my setup with a new webserver routing framework.

1 Answer 1

7

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.
Sign up to request clarification or add additional context in comments.

3 Comments

Is there a way to make that compile step async? I'm working on an embedded system. Lazy loading has made things better, but if I need to require a module for an api, all requests block while that module loads. Bad. News. Bears. y'know?
I've been reading the file, and using vm.runInNewContext, which is the same thing compile does. So it doesn't get loaded as a module, rather it is loaded by me and I use vm to run it. I have to do my own caching, but it does have the advantage of being able to reload a module.
Cool. I may need to use caching tricks for hotloading. I dug a little deeper and found that it isn't currently possible to async load scripts github.com/iojs/io.js/issues/1083.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.