Каков определенный порядок выполнения импорта ES6?

Я пробовал искать в Интернете порядок выполнения импортированных модулей. Например, допустим, у меня есть следующий код:

import "one"
import "two"
console.log("three");

Где one.js и two.js определены следующим образом:

// one.js
console.log("one");

// two.js
console.log("two");

Гарантированно ли вывод на консоль:

one
two
three

Или это не определено?


person Max    schedule 22.02.2016    source источник
comment
импорт синхронизируется, поэтому порядок вывода гарантирован. консоль, показывающая материал, технически асинхронна, но это не имеет значения, потому что она буферизована.   -  person dandavis    schedule 22.02.2016
comment
Независимо от ответа, практическое правило: всякий раз, когда вам требуется определенный порядок оценки, явно объявляйте свои зависимости с помощью import.   -  person Bergi    schedule 23.02.2016


Ответы (1)


Модули JavaScript оцениваются асинхронно. Однако весь импорт оценивается до того, как тело модуля выполнит импорт. Это отличает модули JavaScript от модулей CommonJS в Node или _ 1_ теги без атрибута async. Модули JavaScript ближе к спецификации AMD, когда дело доходит до как они загружены. Подробнее см. раздел 16.6.1 Изучение ES6 Автор Аксель Раушмайер.

Таким образом, в примере, представленном запрашивающим, порядок выполнения не может быть гарантирован. Есть два возможных исхода. Мы можем увидеть это в консоли:

one
two
three

Или мы можем увидеть это:

two
one
three

Другими словами, два импортированных модуля могли выполнять свои console.log() вызовы в любом порядке; они асинхронны относительно друг друга. Но они определенно будут выполнены до тела модуля, который их импортирует, поэтому "three" гарантированно будет занесен в журнал последним.

Асинхронность модулей можно наблюдать при использовании операторы await верхнего уровня (теперь реализованы в Chrome). Например, предположим, что мы немного изменили пример вопрошающего:

// main.js
import './one.js';
import './two.js';
console.log('three');

// one.js
await new Promise(resolve => setTimeout(resolve, 1000));
console.log('one');

// two.js
console.log('two');

Когда мы запускаем main.js, мы видим в консоли следующее (с добавленными метками времени для иллюстрации):

[0s] two
[1s] one
[1s] three
person McMath    schedule 22.02.2016
comment
Любые ссылки на импортированные модули ES6 выполняются асинхронно. - person Benjamin Gruenbaum; 23.02.2016
comment
Насколько мне известно, модули ES2015 не импортируются асинхронно, скорее - то, как они загружаются, полностью зависит от загрузчика модуля. - person Benjamin Gruenbaum; 23.02.2016
comment
@BenjaminGruenbaum Я могу процитировать только свой ответ: Подробнее см. раздел 16.6. 1 книги Exploring ES6 Акселя Раушмайера. - person McMath; 23.02.2016
comment
@BenjaminGruenbaum Да, поэтому я добавляю оговорку, что ни один современный браузер не реализует модули ES6. Я не знаю, следуют ли транспилеры, такие как Babel, оригинальной спецификации в этом отношении. Я подозреваю, что большинство таких транспилеров импортируют синхронно, как вы предлагаете. Но мой ответ касается исходной спецификации. - person McMath; 23.02.2016
comment
Я на самом деле рецензент этой книги. Я хочу сказать, что это не зависит от спецификации модуля ES решать это - это зависит от спецификации модуля loaded, чтобы решить, как загружать модули. Спецификация IIRC требует, чтобы все модули загружались только при выполнении кода. - person Benjamin Gruenbaum; 23.02.2016
comment
@BenjaminGruenbaum Хорошо, похоже, ты знаешь об этом больше, чем я. Не стесняйтесь дать свой ответ. Я буду счастлив снять это, как только покажу, что ошибаюсь. - person McMath; 23.02.2016
comment
Я не хочу, чтобы вы его снимали, я даже не уверен на 100% в этом. Ваш ответ почти правильный, за исключением того, что часть, которая определяет, как это работает в браузерах, должна указывать на то, что это происходит таким образом из-за спецификации загрузчика модуля браузера, а не спецификации ES. Например, узел не привязан к нему. - person Benjamin Gruenbaum; 23.02.2016
comment
@BenjaminGruenbaum Я почти уверен, что намерение состоит в том, чтобы разрешить асинхронное и одновременное разрешение / загрузку / инициализацию модулей (также см. эта формулировка). Однако я должен признать, что спецификация написана в довольно синхронном стиле (особенно оценка модуля ), который является частью одного TopLevelModuleEvaluationJob. Это даже довольно последовательно (с четко определенным порядком), учитывая, что список [[RequestedModules]] повторяется. Так… - person Bergi; 23.02.2016
comment
Мы должны предположить, что HostResolveImportedModule является асинхронным (например, : ждать время, определяемое реализацией, аналогично тому, как указано в спецификации XHR), в течение которого могут выполняться другие очереди заданий, и что он либо рекурсивно планирует задания оценки модулей, либо просто вызывает метод оценки модулей загруженных модулей, как только их больше нет неразрешенные зависимости. - person Bergi; 23.02.2016
comment
@Bergi Спасибо за ваш вклад. Спецификация по-прежнему кажется мне неоднозначной по этому вопросу. Я не уверен, что понимаю, почему HostResolveImportedModule должен быть асинхронным; У меня сложилось впечатление, что это будет зависеть от реализации. Может быть, я просто не в себе по этому поводу. В любом случае, я приглашаю вас внести или предложить какие-либо правки, и я с радостью дам лучший ответ, если он у вас есть. - person McMath; 24.02.2016
comment
Если модули не будут выполняться в порядке импорта (в одном модуле, а не в нескольких тегах HTML-скриптов), тогда библиотеки полифилов, такие как core-js, не будут работать надежно. Я думаю, что этот ответ немного вводит в заблуждение, хотя у меня нет хорошей ссылки в спецификации, чтобы это доказать. - person letmaik; 19.03.2021
comment
@letmaik Все операции импорта выполняются до остальной части кода в файле, поэтому библиотека polyfill (или любая другая библиотека) будет полностью выполнена к тому времени, когда вы ее используете. Единственный сценарий, в котором могут возникнуть проблемы, - это импортировать core-js, за которым следует some-other-module, который зависит от core-js. Но в этом случае some-other-module должен сам импортировать core-js. Тем не менее, это старый ответ. Теперь, когда браузеры фактически реализовали модули, возможно, что на практике импорт выполняется последовательно. Наверное, стоит проверить и обновить ответ. - person McMath; 22.03.2021