[ES6] Ruan Yifeng Implementação de Carregamento do Módulo de Aprendizagem ES6

1. Carregamento do navegador

método tradicional

Em páginas da Web em HTML, os navegadores <script>carregam scripts JavaScript por meio de tags.

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

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

Por padrão, o navegador carrega os scripts JavaScript de forma síncrona, ou seja, o mecanismo de renderização <script>para quando encontra uma tag, aguarda até que o script seja executado e continua a renderizar. Se for um script externo, o tempo de download do script também deve ser adicionado. Se o script for grande, levará muito tempo para baixar e executar, fazendo com que o navegador seja bloqueado, e o usuário sentirá que o navegador está "travado" sem nenhuma resposta. A experiência do usuário é muito ruim.

Portanto, os navegadores permitem que os scripts sejam carregados de forma assíncrona, aqui estão duas sintaxes para carregamento assíncrono.

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

deferou asyncatributo, o script será carregado de forma assíncrona. Quando o mecanismo de renderização encontra essa linha de comando, ele começa a baixar o script externo, mas não espera que ele baixe e execute, mas executa diretamente o seguinte comando.

deferasyncA diferença com

  • deferEle não será executado até que toda a página seja renderizada normalmente na memória (a estrutura DOM é totalmente gerada e outros scripts são executados);

  • asyncApós a conclusão do download, o mecanismo de renderização interromperá a renderização e continuará a renderização após a execução deste script.

Resumir: deferÉ "executar após a renderização" asynce "executar após o download". Além disso, se houver vários deferscripts, eles serão carregados na ordem em que aparecem na página, e vários asyncscripts não podem garantir a ordem de carregamento.

regra de carga

O navegador carrega ES6o módulo, que também usa <script>tags, mas adiciona type="module"atributos.

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

Os módulos ES6 também permitem a incorporação em páginas da web, e a sintaxe e o comportamento são exatamente os mesmos que carregar scripts externos.

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

  // other code
</script>

Precauções:

  • O código é executado no escopo do módulo, não no escopo global. Variáveis ​​de nível superior dentro do módulo, não visíveis fora.
  • Os scripts do módulo adotam automaticamente o modo estrito, declarado ou não use strict.
  • Entre os módulos, você pode usar importcomandos para carregar outros módulos ( .jso sufixo não pode ser omitido, você precisa fornecer URLs absolutas ou relativas) e também pode usar exportcomandos para interfaces externas de saída.
  • Dentro de um módulo, a palavra-chave de nível superior thisretorna undefined, não aponta para window. Em outras palavras, não faz sentido usar a palavra-chave this no nível superior do módulo.
  • Se o mesmo módulo for carregado várias vezes, ele será executado apenas uma vez.

Diferenças entre módulos ES6 e módulos CommonJS

1. Os módulos CommonJS produzem uma cópia de um valor, enquanto os módulos ES6 produzem uma referência a um valor.

// 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. Os módulos CommonJS são carregados em tempo de execução e os módulos ES6 são interfaces de saída em tempo de compilação.

3. O require() do módulo CommonJS carrega o módulo de forma síncrona, e o comando import do módulo ES6 carrega de forma assíncrona, e há uma fase de análise independente das dependências do módulo.

3. Método de carregamento do módulo Node.js

JavaScript agora tem dois tipos de módulos. Um é ES6módulo, abreviado ESM; o outro é CommonJSmódulo, abreviado CJS.

CommonJSO módulo é Node.jsproprietário e ES6incompatível com o módulo. Acima da gramática, a diferença mais óbvia entre os dois é que CommonJSo módulo usa require()e module.exports, e ES6o módulo usa importe export.

Node.jsRequer que ES6os módulos recebam .mjso sufixo de nome de arquivo. importEm outras palavras, desde que o comando ou seja usado no arquivo de script export, o nome do sufixo deve ser usado .mjs. Quando o Node.js encontra .mjsum arquivo, ele o considera um módulo ES6. O modo estrito é ativado por padrão e não precisa ser especificado na parte superior de cada arquivo de módulo "use strict".

Se você não quiser alterar o nome do sufixo para , poderá especificar o campo como no arquivo .mjsde projeto .package.jsontypemodule

{
    
    
   "type": "module"
}

Uma vez definidos, os scripts JS do projeto são interpretados como módulos ES6.

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

Se você quiser usar o módulo CommonJS neste momento, você precisa alterar o nome do sufixo do script CommonJS para .cjs. Se não houver typecampo, ou typese o campo for commonjs, o script .js será interpretado como CommonJSum módulo.

Resumir: .mjsO arquivo é sempre carregado como um módulo ES6, e o arquivo é sempre carregado .cjscomo um módulo, e o carregamento do arquivo depende das configurações dos campos dentro de .CommonJS.jspackage.jsontype

Módulos CommonJS carregam módulos ES6

Comandos CommonJS require()não podem carregar módulos ES6, e um erro será reportado, então import()este método só pode ser usado para carregá-los.

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

require()Uma razão pela qual os módulos ES6 não são suportados é que eles são carregados de forma síncrona, e os comandos de nível superior podem ser usados ​​dentro dos módulos ES6 await, portanto, eles não podem ser carregados de forma síncrona.

Módulos ES6 carregam módulos CommonJS

Os comandos do módulo ES6 importpodem carregar CommonJSmódulos, mas apenas como um todo, não apenas um único item de saída.

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

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

Isso ocorre porque os módulos ES6 precisam oferecer suporte à análise de código estático, enquanto a interface de saída dos módulos CommonJS é module.exportsum objeto que não pode ser analisado estaticamente, portanto, só pode ser carregado como um todo.

O carregamento de um único item de saída pode ser escrito da seguinte maneira.

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

module.createRequire()Há também um método de carregamento alternativo, que é usar o método interno do 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

No código acima, o módulo ES6 module.createRequire()pode carregar CommonJSo módulo através do método. No entanto, esta forma de escrita é equivalente a misturar ES6e , por isso não é recomendado o seu uso.CommonJS

Acho que você gosta

Origin blog.csdn.net/Bon_nenul/article/details/128317499
Recomendado
Clasificación