мое понимание модулей ES правильное - PullRequest
0 голосов
/ 02 сентября 2018

В последнее время я думал о модулях ES, и вот как я думаю, они работают:

  1. Существует глобальный объект, к которому пользователь не может получить доступ (назовем его #moduleMap). Он отображает абсолютные адреса модулей для их экспорта:
#moduleMap = {
  "https://something.com/module.mjs": { exportName: "value" }
}
  1. Процедура оценки модуля выглядит следующим образом:
    • модуль загружен
    • модуль разбирается на ast
    • ast изменяется следующим образом:

import { x } from "./module1.mjs" => все ссылки x заменены на #moduleMap["abs path module1.mjs"].x (и импортируемый модуль извлекается)

export const y = "some value" => #moduleMap["abs path to this module"].y = "some value"

(как отметил @Bergi, с экспортом не все так просто, потому что экспорт не поднимается, поэтому мертвая зона для витков и подъем для функций не отражаются только при присваивании свойств)

(вышеупомянутое - это то, что называется связыванием, которое производит «живые привязки»)

  • операция повторяется для каждого импортируемого модуля
  • когда все модули извлекаются, анализируются и изменяются, оценка начинается с модуля ввода (каждый модуль выполняется изолированно (~ вызывается в IIFE с включенным строгим режимом).

Как указывал @Bergi, модули оцениваются с нетерпением, начиная с модуля ввода и оценивая импорт модуля перед выполнением самого кода модуля (за исключением циклических зависимостей), что практически означает, что импорт, который требовался последним, будет выполняться первым.

  • когда оценка достигает любого кода, который обращается к #moduleMap["some module"], браузер проверяет, был ли оценен модуль если оно не было оценено, оно оценивается в этот момент, после чего оценка возвращается в это место (теперь модуль (или его экспорт, если быть точным) «кэшируется» в #moduleMap)
  • если он был оценен, импорт доступен с #moduleMap["some module"].someImport
для ситуаций, когда импорт переназначается из другого модуля, браузер выдает ошибку

Это в основном все, что происходит AFAIK. Я прав?

Ответы [ 2 ]

0 голосов
/ 02 сентября 2018

export const y = "some value" => #moduleMap["abs path to this module"].y = "some value"

(вышесказанное - это то, что называется связыванием, которое производит «живые привязки»)

Да, в принципе - вы правильно поняли, что все они ссылаются на одно и то же, и когда модуль переназначит его, импортеры заметят это.

Однако, это немного сложнее, так как const y остается объявлением переменной const, поэтому оно все еще подчиняется временной мертвой зоне, а объявления function по-прежнему подлежат подъему. Это плохо отражается, когда вы рассматриваете экспорт как свойства объекта.

  • когда оценка достигает любого кода, который обращается к #moduleMap["some module"], браузер проверяет, был ли оценен модуль
    • если он не был оценен, он оценивается в этот момент, после чего оценка возвращается в это место (теперь модуль (или его экспорт, если быть точным) «кэшируется» в #moduleMap)
    • если он был оценен, импорт доступен с #moduleMap["some module"].someImport

Нет. Оценка модуля не происходит лениво, когда интерпретатор сталкивается с первой ссылкой на импортированное значение. Вместо этого модули оцениваются строго в порядке операторов import (начиная с модуля ввода). Модуль не начинает оцениваться до того, как будут оценены все его зависимости (кроме случаев, когда он имеет циклическую зависимость от себя).

0 голосов
/ 02 сентября 2018

У вас довольно хорошее понимание, но есть несколько аномалий, которые следует исправить.

ES Модули

В ECMA-262 все модули будут иметь такую ​​общую форму:

Abstract Module {
  Environment // Holds lexical environment for variables declared in module
  Namespace   // Exotic object that reaches into Environment to access exported values

  Instantiate()
  Evaluate()
}

Существует много разных мест, откуда могут поступать модули, поэтому есть "подклассы" этого Абстрактного модуля . Тот, о котором мы здесь говорим, называется Исходный текстовый модуль .

Source Text Module : Abstract Module {
  ECMAScriptCode     // Concrete syntax tree of actual source text
  RequestedModules   // List of imports parsed from source text
  LocalExportEntries // List of exports parsed from source text

  Evaluate()         // interprets ECMAScriptCode
}

Когда переменная объявляется в модуле (const a = 5), она сохраняется в Environment модуля. Если добавить к этому объявление export, оно также будет отображаться в LocalExportEntries.

Когда вы import модуль, вы фактически захватываете объект Namespace, который имеет экзотическое поведение, что означает, что, хотя он кажется нормальным объектом, такие вещи, как получение и установка свойств, могут делать разные вещи, чем вы ожидали.

В случае Объекты пространства имен модуля , получив свойство namespace.a, фактически ищет это свойство как имя в ассоциированном Environment.

Итак, если у меня есть два модуля, A и B:

// A
export const a = 5;
// B
import { a } from 'A';

console.log(a);

Модуль B импортирует A, а затем в модуле B a связывается с A.Namespace.a. Поэтому, когда к модулю b осуществляется доступ к a, он на самом деле ищет его в A.Namespace, а в A.Environment. (Вот как на самом деле работают живые привязки).

Наконец, на тему карты вашего модуля. Все модули будут созданы до того, как их можно будет оценить. Instantiation - это процесс разрешения графа модуля и подготовки модуля для оценки.

Модуль Карта

Идея «карты модулей» зависит от конкретной реализации, но для браузеров и узлов она выглядит следующим образом: Module Map <URL, Abstract Module>.

Хороший способ показать, как браузеры / узлы используют этот модуль, карта динамическая import():

async function import(specifier) {
  const referrer = GetActiveScriptOrModule().specifier;
  const url = new URL(specifier, referrer);
  if (moduleMap.has(url)) {
    return moduleMap.get(url).Namespace;
  }
  const module = await FetchModuleSomehow(url);
  moduleMap.set(url, module);
  return module.Namespace;
}

Вы можете увидеть это точное поведение в Node.js: https://github.com/nodejs/node/blob/e24fc95398e89759b132d07352b55941e7fb8474/lib/internal/modules/esm/loader.js#L98

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...