[ES6] Ruan Yifeng ES6 Learning Module Loading Implementation

1. Browser loading

traditional method

In HTML web pages, browsers <script>load JavaScript scripts through tags.

<!-- 页面内嵌的脚本 -->
<script type="application/javascript">
  // module code
</script>

<!-- 外部脚本 -->
<script type="application/javascript" src="path/to/myModule.js">
</script>

By default, the browser loads JavaScript scripts synchronously, that is, the rendering engine <script>will stop when it encounters a tag, wait until the script is executed, and then continue to render down. If it is an external script, the script download time must also be added. If the script is large in size, it will take a long time to download and execute, thus causing the browser to be blocked, and the user will feel that the browser is "stuck" without any response. The user experience is very poor.

So browsers allow scripts to be loaded asynchronously, here are two syntaxes for asynchronous loading.

<script src="path/to/myModule.js" defer></script>
<script src="path/to/myModule.js" async></script>

deferor asyncattribute, the script will load asynchronously. When the rendering engine encounters this line of command, it will start to download the external script, but it will not wait for it to download and execute, but directly execute the following command.

deferasyncThe difference with

  • deferIt will not be executed until the entire page is rendered normally in memory (the DOM structure is completely generated, and other scripts are executed);

  • asyncOnce the download is complete, the rendering engine will interrupt the rendering, and continue rendering after executing this script.

Summarize: deferIt is "execute after rendering", asyncand "execute after downloading". In addition, if there are multiple deferscripts, they will be loaded in the order in which they appear on the page, and multiple asyncscripts cannot guarantee the loading order.

load rule

The browser loads ES6the module, which also uses <script>tags, but adds type="module"attributes.

<script type="module" src="./foo.js"></script>

ES6 modules also allow embedding in web pages, and the syntax and behavior are exactly the same as loading external scripts.

<script type="module">
  import utils from "./utils.js";

  // other code
</script>

Precautions:

  • Code is run at module scope, not at global scope. Top-level variables inside the module, not visible outside.
  • Module scripts automatically adopt strict mode, whether declared or not use strict.
  • Among the modules, you can use importcommands to load other modules ( .jsthe suffix cannot be omitted, you need to provide absolute or relative URLs), and you can also use exportcommands to output external interfaces.
  • Within a module, the top-level thiskeyword returns undefined, not points to window. In other words, it is meaningless to use the this keyword at the top level of the module.
  • If the same module is loaded multiple times, it will only be executed once.

Differences between ES6 modules and CommonJS modules

1. CommonJS modules output a copy of a value, while ES6 modules output a reference to a value.

// lib.js
var counter = 3;
function incCounter() {
    
    
  counter++;
}
module.exports = {
    
    
  counter: counter,
  incCounter: incCounter,
};
// main.js
var mod = require('./lib');

console.log(mod.counter);  // 3
mod.incCounter();
console.log(mod.counter); // 3
// lib.js
var counter = 3;
function incCounter() {
    
    
  counter++;
}
module.exports = {
    
    
  get counter() {
    
    
    return counter
  },
  incCounter: incCounter,
};

2. CommonJS modules are loaded at runtime, and ES6 modules are output interfaces at compile time.

3. The require() of the CommonJS module loads the module synchronously, and the import command of the ES6 module loads asynchronously, and there is an independent parsing phase of module dependencies.

3. Node.js module loading method

JavaScript now has two kinds of modules. One is ES6module, abbreviated ESM; the other is CommonJSmodule, abbreviated CJS.

CommonJSThe module is Node.jsproprietary and ES6incompatible with the module. Above the grammar, the most obvious difference between the two is that CommonJSthe module uses require()and module.exports, and ES6the module uses importand export.

Node.jsRequires ES6modules to take .mjsthe suffix filename. importIn other words, as long as the or command is used in the script file export, the suffix name must be used .mjs. When Node.js encounters .mjsa file, it considers it to be an ES6 module. Strict mode is enabled by default and does not have to be specified at the top of each module file "use strict".

If you don't want to change the suffix name to , you can specify the field as in the .mjsproject file .package.jsontypemodule

{
    
    
   "type": "module"
}

Once set, the project's JS scripts are interpreted as ES6 modules.

# 解释成 ES6 模块
$ node my-app.js

If you want to use the CommonJS module at this time, you need to change the suffix name of the CommonJS script to .cjs. If there is no typefield, or typeif the field is commonjs, the .js script will be interpreted as CommonJSa module.

Summarize: .mjsThe file is always loaded as an ES6 module, and the file is always loaded .cjsas a module, and the loading of the file depends on the settings of the fields inside .CommonJS.jspackage.jsontype

CommonJS modules load ES6 modules

CommonJS require()commands cannot load ES6 modules, and an error will be reported, so import()this method can only be used to load them.

// 在 CommonJS 模块中运行
(async () => {
    
    
  await import('./my-app.mjs');
})();

require()One reason why ES6 modules are not supported is that they are loaded synchronously, and top-level commands can be used inside ES6 modules await, so they cannot be loaded synchronously.

ES6 modules load CommonJS modules

ES6 module importcommands can load CommonJSmodules, but only as a whole, not just a single output item.

// 正确
import packageMain from 'commonjs-package';

// 报错
import {
    
     method } from 'commonjs-package';

This is because ES6 modules need to support static code analysis, while the output interface of CommonJS modules is module.exportsan object that cannot be statically analyzed, so it can only be loaded as a whole.

Loading a single output item can be written as follows.

import packageMain from 'commonjs-package';
const {
    
     method } = packageMain;

There is also an alternative loading method, which is to use the built-in module.createRequire()method of Node.js.

// cjs.cjs
module.exports = 'cjs';

// esm.mjs
import {
    
     createRequire } from 'module';

const require = createRequire(import.meta.url);

const cjs = require('./cjs.cjs');
cjs === 'cjs'; // true

In the above code, the ES6 module module.createRequire()can load CommonJSthe module through the method. However, this way of writing is equivalent to mixing ES6and , so it is not recommended to use.CommonJS

Guess you like

Origin blog.csdn.net/Bon_nenul/article/details/128317499
Recommended