23

I was browsing the source code for a command line utility in Node, and saw the following code.

function help() {
    var colors = require('colors');
    var package = require('../package');
    ....
    ....
}

I had not seen require being used inside a function in this way before. I always assumed it was best practice to include it at the top of the file. This is the entry file for this program, and this function is only called in a specific case--but those packages are used elsewhere in the program. When I asked the author of the code for his reasoning, he simply stated that he "didn't want to import all the libraries at once."

Is this good/bad practice? Are there significant implications to load-up time by not requiring these packages at the top of the module, and instead only when these functions are invoked?

jfriend00
  • 683,504
  • 96
  • 985
  • 979
Kevin
  • 273
  • 1
  • 2
  • 6
  • it's not clear what are you asking about, just an advice? – Farside Mar 05 '16 at 17:10
  • It means include required things wherever and whenever needed and not all at once – RIYAJ KHAN Mar 05 '16 at 17:11
  • 3
    One potential downside is that you introduce synchronous I/O into the runtime behavior of your server which is generally considered a bad design pattern. Now fortunately, `require()` works off a cache so the sync I/O only happens the first time the function is called which limits the impact and it's probably local disk I/O and parsing and running of a file of JS (and potentially its dependent modules), but still not considered a best practice. Usually, it is better to accept a little more load time rather than slow down a request handler. – jfriend00 Mar 05 '16 at 17:45

3 Answers3

14

UPDATE: I think a better answer is here: Lazy loading in node.js

MY INITIAL COMMENTS: Well it's a matter of practice, some guys like it at the top while some like lazy-loading. In my opinion both are good, and should be used as per need, so I think that author is right here, because loading a whole bunch libraries at the startup would overload the module with much of the stuff that is never used, and hence would increase the load-time. And although loading the libraries on demand is a synchronous operation, but if we look help method as an entity, then it would give an asynchronous module loading effect (see AMD, which is a popular pattern).

Lazy loading is also a good selection if you have to make a choice between which libraries to load in a particular case, like for example

var isOSX;
// some code here which finds if this is OSX
// then this
if (isOSX === true) {
  var platformHelper = require('supercoolosxhelper');
} else {
  var platformHelper = require('yetanothercoolhelper');
}

In short, you should anticipate in your code if the probability of using a method is high or even mid, then you should require at the top, otherwise if it's low then it would be nice if the module is required on need basis.

Community
  • 1
  • 1
Ammar Hasan
  • 2,436
  • 16
  • 22
7

In the case of Node, it really comes down to mostly a style choice.

Loading a module from disk takes hardly any time at all, so there really isn't anything there in terms of performance gain. Some folks like to keep modules as close to the point where they will be used, that's all.

Now, client side, its all different and is heavily based upon your package manager.

Jeremy J Starcher
  • 23,369
  • 6
  • 54
  • 74
  • 9
    Remember, it's not just loading a single module. It's loading a module and all its dependent modules and all their dependent modules, etc... A single `require()` could actually end up loading a lot of modules depending upon what that module ends up pulling in. – jfriend00 Mar 05 '16 at 17:48
2

It has its own pros and cons. But generally you should avoid it. Here is a good explanation why:

First scenario: imagine I had only module a.js and b.js. Module a.js requires b.js and module b.js requires c.js. If they require at the top of the module I will get alerted when I launch my application that module c.js was not found and the server would crash before I ever went to deploy it. If b.js and c.js are required in functions the error may go undetected until the server is deployed, at which time the entire server will crash when Node attempts to load module c.js possibly several days later if the route requiring that module is one rarely used.

Second scenario: imagine I had a module that took 30 minuets to load, which is unreasonable, but just imagine. If that module is only needed in one route handler it might take some time before someone triggers that route and Node has to require that module. When this happens the server would effectively be inaccessible for 30 minutes as that module is loaded. If this happens at peak hours several of my users might become unhappy and leave. In the end requiring that module in a function vs at the top of a module consumes the same amount of memory, but requiring at the top of a module means it will always be ready to go when someone requests that route and you would instead factor that extra 30 minuets into your deployment time, not at 3am in the morning when a client calls complaining that their site is down.

Sergey Podobry
  • 7,101
  • 1
  • 41
  • 51