O que acontece quando um módulo JS é importado duas vezes?

Vamos começar este artigo com uma pergunta. O módulo ES2015 incrementcontém o seguinte código:

// increment.js
let counter = 0;
counter++;

export default counter;

Em outro módulo, que chamaremos consumer, o módulo acima é importado 2 vezes:

// consumer.js
import counter1 from './increment';
import counter2 from './increment';

counter1; // => ???
counter2; // => ???

E agora, na verdade, uma pergunta. O que entra nas variáveis counter1e counter2depois do módulo consumer? Para responder a essa pergunta, você precisa entender como o JavaScript executa os módulos e como eles são importados.





Execução do módulo


Para entender como os mecanismos internos do JavaScript funcionam, é útil examinar a especificação .

De acordo com a especificação, cada módulo JavaScript está associado a uma entidade de Registro de módulo . Esta entrada possui um método Evaluate()que o módulo executa:

Se este módulo já foi executado com sucesso, retorne indefinido; [...] Caso contrário, execute transitivamente todas as dependências deste módulo e, em seguida, execute este módulo.
Como resultado, verifica-se que o mesmo módulo é executado apenas uma vez.

Infelizmente, o que você precisa saber para responder à nossa pergunta não se limita a isso. Como garantir que a chamada de instruçãoimport usando os mesmos caminhos retornará o mesmo módulo?

Permitir comandos de importação


A operação abstrata HostResolveImportedModule () é responsável por associar o caminho ao módulo (especificador) com um módulo específico . O código de importação do módulo é assim:

import module from 'path';

Aqui está o que a especificação diz sobre isso:

Uma implementação do HostResolveImportedModule deve atender aos seguintes requisitos:

  • O valor normal de retorno deve ser uma instância de uma subclasse específica de Module Record.
  • Se a entidade Record do módulo correspondente ao par que faz referência ao ScriptOrModule, o especificador não existir, ou tal entidade não puder ser criada, uma exceção será lançada.
  • Cada vez que essa operação é chamada transmitindo a ela como argumentos um par específico de especificadorScriptOrModule, referenciador, no caso de sua execução usual, retorne a mesma instância da entidade Record do Módulo.

Agora considere isso de uma maneira mais compreensível.

HostResolveImportedModule(referencingScriptOrModule, specifier)- uma operação de resumo que retorna do módulo correspondente a um par de parâmetros referencingScriptOrModule, specifier:

  • O parâmetro referencingScriptOrModuleé o módulo atual, ou seja, o módulo que importa.
  • Um parâmetro specifieré uma string que corresponde ao caminho do módulo na instrução import.

No final da descrição, HostResolveImportedModule()diz-se que, ao importar módulos que correspondem ao mesmo caminho, o mesmo módulo é importado:

import moduleA from 'path';
import moduleB from 'path';
import moduleC from 'path';

// moduleA, moduleB  moduleC -    

moduleA === moduleB; // => true
moduleB === moduleC; // => true

Curiosamente, a especificação indica que o host (navegador, ambiente Node.js, em geral - qualquer coisa que tente executar o código JavaScript) deve fornecer uma implementação específica HostResolveImportedModule().

Responda


Após uma leitura cuidadosa da especificação, fica claro que os módulos JavaScript são executados apenas uma vez durante a importação. E ao importar um módulo usando o mesmo caminho, a mesma instância do módulo é retornada.

Vamos voltar à nossa pergunta.

Um módulo é incrementsempre executado apenas uma vez:

// increment.js
let counter = 0;
counter++;

export default counter;

Independentemente de quantas vezes um módulo foi importado increment, uma expressão é counter++avaliada apenas uma vez. Uma variável counterexportada usando o mecanismo de exportação padrão é importante 1.

Agora dê uma olhada no módulo consumer:

// consumer.js
import counter1 from './increment';
import counter2 from './increment';

counter1; // => 1
counter2; // => 1

Os comandos import counter1 from './increment'e import counter2 from './increment'usam o mesmo caminho - './increment'. Como resultado, verifica-se que a mesma instância do módulo é importada.

Acontece que o mesmo valor 1 é gravado nas variáveis counter1e counter2em consumer.

Sumário


Depois de examinar uma pergunta simples, pudemos descobrir mais sobre como os módulos JavaScript são executados e importados.

As regras usadas na importação de módulos são bastante simples: o mesmo módulo é executado apenas uma vez. Em outras palavras, o que está no escopo do nível do módulo é executado apenas uma vez. Se um módulo que já foi executado uma vez for importado novamente, ele não será executado novamente. Ao importar um módulo, ele usa o que foi obtido como resultado de uma sessão anterior para descobrir exatamente o que ele exporta.

Se um módulo for importado várias vezes, mas o especificador do módulo (caminho para ele) permanecer o mesmo, a especificação JavaScript garantirá que a mesma instância do módulo seja importada.

Queridos leitores! Com que frequência você recorre à leitura da especificação JavaScript, descobrindo os recursos do funcionamento de certas construções de linguagem?


All Articles