Question

For instance, I have app.js to have a Module object:M by loading(require) a file:_core.js, then properties of M are to add by loading(require) files under a directory: ./Project_Functions/

var Project_FunctionsDIR = './Project_Functions/';
var Project_coreFile = '_core.js';

var M = require(Project_FunctionsDIR + Project_coreFile);

require("fs")
  .readdir(Project_FunctionsDIR,
    function(err, files)
    {
      files.forEach(function(file)
      {
        if (file !== Project_coreFile)
        {
          var name = file.split('.js')[0]; 
          var filepath = Project_FunctionsDIR + file;
          M[name] = require(filepath); 
        }
      });
    });
console.log('module.exports');
module.exports = M;

Here, the constructed moduleObject:M is exported by module.exports.

Please note the fs.readdir is async, so module.exports = M; is evaluated before M properties are constructed in app.js.

Now, I want to test this object M in test.js,

var expect = require('chai').expect;

var M = require('./app.js');
//........

On var M = require('./app.js'); line, the app.js is evaluated, which indicates that the M object is exported before the whole properties are constructed.

In fact, I inserted setTimeout at the fs.readdir callback, the test fails obviously the M object is not ready yet.

Firstly, I thought module.exports = M; should be put within the fs.readdir callback, but if I do that, now var M = require(Project_FunctionsDIR + Project_coreFile); part fails, probably because module.exports = M; is not exposed to read properly.

Yes, this can be resolved simply by using fs.readdirSync and actually, I have been doing so when I encounter this sort of problem, however, I always feel uncomfortable to use node Sync methods and rather try to seek a smarter work-around.

So, here's my question; is it possible by not using Sync method for this issue? or impossible?

Furthermore, I'd like to ask more in general.

Can we do anything without using Sync methods, or in some cases, we must use Sync methods in node.js?

In functional programming scheme, Sync methods should be avoided if possible since the Sync concept depends on not function(callback) but time.

Thanks for your thought.


EDIT:

I've just found a related topic here: Asynchronous initialization of Node.js module

The conclusion is we must use Sync method to correspond a Sync method. In this case, require is a sync method.

Was it helpful?

Solution

A common pattern is for the module to expose an asynchronous initialize method that does the asynchronous work. For your module, it would look like this:

var Project_FunctionsDIR = './Project_Functions/';
var Project_coreFile = '_core.js';

var M = require(Project_FunctionsDIR + Project_coreFile);

M.initialize = function(next) {
  require("fs")
  .readdir(Project_FunctionsDIR,
    function(err, files)
    {
      files.forEach(function(file)
      {
        if (file !== Project_coreFile)
        {
          var name = file.split('.js')[0]; 
          var filepath = Project_FunctionsDIR + file;
          M[name] = require(filepath); 
        }
      });
      next();
    });
}
module.exports = M;

Then you can test it with:

var M = require('./app.js');
M.initialize(function() {
  //........
}

This is a useful pattern because many asynchronous methods don't have synchronous versions, and it allows you to run many of these asynchronous initializes in parallel, drastically reducing startup time for larger apps.

OTHER TIPS

node.js uses CommonJS module pattern, which by definition export their exposed objects synchronously on load. What you're trying to do is not possible asynchronously, although you can do it just by exposing the other files into your 'main' export. If you want to dynamically expose all files in a directory from one object, just use the synchronous readdir, it'll only be executed on start up.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top