Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

Is the module in NodeJS a singleton?

2025-02-24 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/02 Report--

This article introduces the knowledge of "is the module in NodeJS a singleton?". In the operation of actual cases, many people will encounter such a dilemma. Then let the editor lead you to learn how to deal with these situations. I hope you can read it carefully and be able to achieve something!

The module of NodeJS is singleton by default, but it does not guarantee that it must be a singleton as we imagine when programming. According to the official document of NodeJS, whether a module import is a singleton is affected by the following two factors:

The caching mechanism of the Node module is case-sensitive, for example, if you require ('/ foo') and require ('/ FOO') return two different objects, even though your foo and FOO are exactly the same file.

Modules are cached based on their parsed file names, and since different modules rely on the path in which they are called for cache authentication, there is no guarantee that you will always return the same object if you use require ('foo'). You may get different objects according to different file paths.

Create a new NodeJS module

According to the NodeJS documentation, there is an one-to-one correspondence between files and modules. This is also the basis for explaining the module caching mechanism mentioned above, let's first create a simple module:

/ / counter.js let value = 0 module.exports = {increment: () = > value++, get: () = > value,}

In counter.js, we create a private variable that can only be manipulated through the public increment and get methods. In application, we can use this module in the following ways:

/ / app.js const counter = require ('. / counter.js') counter.increment () counter.increment () console.log (counter.get ()) / / prints 2 console.log (counter.value) / / prints undefined as value is private

Module Caching

NodeJS caches a module after it is imported for * times, as described in the official document:

Every call to require ('foo') will get exactly the same object returned, if it would resolve to the same file.

We can also verify this sentence with the following simple examples:

/ / app-singleton.js const counter1 = require ('. / counter.js') const counter2 = require ('. / counter.js') counter1.increment () counter1.increment () counter2.increment () console.log (counter1.get () / prints 3 console.log (counter2.get ()) / / also prints 3

You can see that although we imported the module twice, we still pointed to the same object. But not every time we import the same module, we get the same object. In NodeJS, the module object has a built-in method: Module._resolveFilename (), which is responsible for finding the appropriate module in require and, after finding the correct file, uses its file name as the cache key name. The pseudo code of the official search algorithm is:

Require (X) from module at path Y 1. If X is a core module, a. Return the core module b. STOP 2. If X begins with'. /'or'/'or'.. /'a. LOAD_AS_FILE (Y + X) 1. If X is a file, load X as JavaScript text. STOP 2. If X.js is a file, load X.js as JavaScript text. STOP 3... 4... B. LOAD_AS_DIRECTORY (Y + X) 1. If X/package.json is a file, a. Parse X/package.json, and look for "main" field. B. let M = X + (json main field) c. LOAD_AS_FILE (M) 2. If X/index.js is a file, load X/index.js as JS text. STOP 3... 4... LOAD_NODE_MODULES (X, dirname (Y)) 4. THROW "not found"

In a nutshell, the logic or priority of loading is:

Give priority to judging whether it is the core module.

Search node_modules if it is not the core module

Otherwise, search in the relative path

The parsed file name can be obtained based on the module object or:

/ / counter-debug.js console.log (module.filename) / / prints absolute path to counter.js console.log (_ filename) / / prints same as above / / I get: "/ Users/laz/repos/medium/modules/counter-debug.js" let value = 0 module.exports = {increment: () = > value++, get: () = > value

In the above example, we can see that the parsed file name is even the absolute path of the loaded module. According to the principle of one-to-one mapping between files and modules, we can draw the following two special cases that will destroy the singleton nature of module import.

Case Sensitivity

In a case-sensitive file system or operating system, different parsed files may point to the same file, but their cache key names will be different, that is, different imports will generate different objects.

/ / app-no-singleton-1.js const counter1 = require ('. / counter.js') const counter2 = require ('. / COUNTER.js') counter1.increment () console.log (counter1.get ()) / / prints 1 console.log (counter2.get ()) / / prints 0, not same object as counter1 / * We have two different resolved filenames:-"Users/laz/repos/medium/modules/counter.js"-"Users/laz/repos/medium/modules/COUNTER.js" * /

In the above example, we use counter and COUNTER respectively to import the same file in different case. If it is in a case-sensitive system, such as UBUNTU, an exception will be thrown directly:

Resolve to different file names

When we use require (x) and x is not part of the core module, it automatically searches the node_modules folder. Before npm3, projects installed dependencies in a nested manner. So when our project relies on module-an and module-b, and module-an and module-b depend on each other, it generates the following file path format:

/ / npm2 installed dependencies in nested way app.js package.json node_modules/ |-module-a/index.js |-module-b/index.js |-node_modules |-module-a/index.js

In this case, we have two copies of the same module, so when we import module-an in the application, how can we load the following files:

/ / app.js const moduleA = require ('module-a') loads: "/ node_modules/module-a/index.js"

When you load module-a from module-b, it loads the following files:

/ node_modules/module-b/index.js const moduleA = require ('module-a') loads "/ node_modules/module-b/node_modules/module-a/index.js"

However, after npm3, it loads files in a flat manner, and the file directory structure is as follows:

/ / npm3 flattens secondary dependencies by installing in same folder app.js package.json node_modules/ |-module-a/index.js |-module-b/index.js

However, there is another scenario, that is, our application itself depends on module-a@v1.1 and module-b, while module-b depends on module-a@v1.2, in which case we still adopt a nested directory structure similar to that before npm3. In this way, different objects will also be generated for module-a, but they will be different files at this time, so they will not conflict with each other.

This is the end of the content of "is the module in NodeJS a singleton?" Thank you for your reading. If you want to know more about the industry, you can follow the website, the editor will output more high-quality practical articles for you!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report