Node.js - module caching, partially executed objects and circular dependencies?

The node.js documentation on module caching provides the following statement:

Multiple calls requiring ('foo') cannot cause module code to execute multiple times. This is an important feature. With it, objects with "partially executed" can be returned, which allows you to load transitive dependencies, even if they will cause loops.

I am a little confused about the last sentence. What is a "partially completed" object? How does this relate to resolving (or avoiding) circular dependencies?

+6
source share
2 answers

If you require package from a file, and this leads to the fact that the file in this package will require file that called the initial require , then you have a circular dependency. By default, it just goes in a circle. To avoid this, you can save the marker where the initial require began, so the next time this file is require , it will start from that point, not from the beginning. This is not perfect, but if you download a package, you are usually only interested in exporting, in which case it works well.

I pressed diff for node-browsersify a while ago for a primitive "partially completed" export method. Basically, every time something is require , it checks the export volume. If there is more export, it means that the package was incomplete for the last time and can still be processed. If there is no new export (the new and old counters are equal), then this means that the package has been executed and can be cached so that the module code does not execute several times. Since it is located in the browser, there is no control over the flow of execution, and, therefore, the module code will be repeated partially (in stages) until completion. If I'm sure Node.js has more elegant management.

+5
source

There is a good and clear example provided in the node.js documentation . It sheds more light on the object "partially executed" and cyclical dependencies.

When there are calls to circle require (), the module may not have completed execution when it is returned.

Consider this situation:

a.js:

 console.log('a starting'); exports.done = false; const b = require('./b.js'); console.log('in a, b.done = %j', b.done); exports.done = true; console.log('a done'); 

b.js:

 console.log('b starting'); exports.done = false; const a = require('./a.js'); console.log('in b, a.done = %j', a.done); exports.done = true; console.log('b done'); 

main.js:

 console.log('main starting'); const a = require('./a.js'); const b = require('./b.js'); console.log('in main, a.done=%j, b.done=%j', a.done, b.done); 

When main.js loads a.js, then a.js takes turns loading b.js. At this point, b.js is trying to download a.js. To prevent an infinite loop, an incomplete copy of the a.js export object is returned to the b.js module. Then b.js completes the download, and the export object is provided to the a.js. module.

By the time main.js loaded both modules, they were both finished. The result of this program will be:

node main.js

 main starting a starting b starting in b, a.done = false b done in a, b.done = true a done in main, a.done=true, b.done=true 
0
source

Source: https://habr.com/ru/post/890116/


All Articles