By Dmitri Pavlutin
Translation: Crazy geek
Dmitripavlutin.com/javascript-…
Reproduced without permission
Let’s start with a question.
The ES2015 module named Increment contains the following code:
// increment.js
let counter = 0;
counter++;
export default counter;
Copy the code
In the consumer module, import the above module increment twice:
// consumer.js
import counter1 from './increment';
import counter2 from './increment';
counter1; / / = >???
counter2; / / = >???
Copy the code
The question is: what are the contents of the variables counter1 and counter2 when the consumer module runs?
To answer this question, you first need to understand how JavaScript evaluates and imports modules.
1. Module evaluation
A good way to understand the inner workings of JavaScript is to look at its instructions.
According to the specification, each JavaScript module is associated with a module record. The module record has the Evaluate() method, which evaluates the module:
If the module has been successfully evaluated, undefined is returned; … Otherwise, all module dependencies for this module can be evaluated recursively, and then the module can be evaluated.
So the same module is evaluated only once.
Unfortunately, the problem does not stop there. How do I ensure that the same module is returned from two calls to import statements using the same path?
2. Resolve the import problem
The paths (also known as specifier) associated with specific module duties by HostResolveImportedModule () to perform operations.
import module from 'path';
Copy the code
According to the rules:
The realization of the HostResolveImportedModule must meet the following requirements:
- The normal return value must be
Module Record
An instance of a concrete subclass of. - If the
referencingScriptOrModule, specifier
Student: Corresponding toModule Record
If it does not exist or cannot be created, an exception must be thrown. - Use specific ones each time
referencingScriptOrModule, specifier
When this operation is called as an argument, it must return the same if it completes normallyModule Record
Instance.
Let’s look at what’s happening in a way that’s easy to understand.
HostResolveImportedModule (referencingScriptOrModule, specifiers) is an abstract operation, The operation returns corresponding to ReferencingScriptOrModule, specifiers module:
- parameter
referencingScriptOrModule
Is the current module, that is, the module to import. - parameter
specifier
Is the correspondingimport
The string of the module path in the statement.
Finally, HostResolveImportedModule () from the same path import module, will import the same module:
import moduleA from 'path';
import moduleB from 'path';
import moduleC from 'path';
// moduleA, moduleB and moduleC are equal
moduleA === moduleB; // => true
moduleB === moduleC; // => true
Copy the code
It is interesting to note that specification is pointed out that the host (refers to the browser, the Node or anything to try to run JavaScript) must provide HostResolveImportedModule () implementation.
3. The answer
After reviewing the specification, you will know that the JavaScript module has been evaluated. In addition, when a module is imported from the same path, the same module instance is returned.
Let’s go back to the question.
The INCREMENT module is always evaluated once:
// increment.js
let counter = 0;
counter++;
export default counter;
Copy the code
No matter how many times the increment module is imported, the counter++ statement is executed only once. The default exported counter variable has a value of 1.
Now look at the Consumer module:
// consumer.js
import counter1 from './increment';
import counter2 from './increment';
counter1; / / = > 1
counter2; / / = > 1
Copy the code
Import Counter1 from ‘./increment’ and Import Counter2 from ‘./increment’ have the same path: ‘./increment’. So you will import the same module instance.
Finally, both the counter1 and Counter2 variables inside the consumer are equal to 1.
4. Conclusion
Detailed information on how to evaluate and import JavaScript modules can be found by simply examining the simple questions posed.
The rule is simple: the same module is evaluated only once, in other words, module-level actions are performed only once. If the evaluated module is imported again, the second evaluation is skipped and the resolved exported file is used.
If a module is imported multiple times but uses the same specifier (that is, path), the JavaScript specification ensures that you will get the same module instance.