Модули JavaScript (также известные как модули ES6) всегда выполняются в одном и том же предопределенном порядке.
Когда модуль импортирует другие модули, порядок, в котором выполняются все модули, гарантированно будет одинаковым. Порядок называется обход пост-заказа слева направо. Перед выполнением модуля (родительского) выполняются все импортируемые им модули (дочерние модули). Дочерние модули выполняются в том порядке, в котором они указаны в операторах import
родительского модуля. Давайте проведем несколько экспериментов, чтобы продемонстрировать это.
Полный код трех тестов можно скачать с Github https://github.com/marianc000/executionOrderModules.
Порядок выполнения дочерних модулей
Для первой демонстрации я создаю восемь идентичных дочерних модулей a, b, c, d, e, f, g, h. Каждый из них содержит только одну строку кода - вызов глобальной функции recordExecution
с URL-адресом модуля в качестве аргумента (модули могут получать свои URL-адреса из объекта import.meta
, зависящего от модуля).
recordExecution(import.meta.url);
Вспомогательная функция recordExecution
извлекает имя модуля из URL-адреса и добавляет его в конец глобального массива exections
. recordExecution
служит для записи выполнения модуля. После выполнения всех модулей массив exections
будет содержать порядок их выполнения.
const re = /\/([a-z])\.js$/; const exections = []; function recordExecution(url) { // http://127.0.0.1:5500/Execution/js/a.js => a exections.push(re.exec(url)[1]); }
Родительский модуль i импортирует восемь дочерних модулей и проверяет историю.
import './a.js'; import './b.js'; import './c.js'; import './d.js'; import './e.js'; import './f.js'; import './g.js'; import './h.js'; recordExecution(import.meta.url); const order=exections.join(''); console.assert(order==='abcdefghi',order);
Для выполнения модулей в браузере я использую тег script
:
<script src="js/i.js" type="module"></script>
В консоли браузера вы можете видеть, что девять примеров модулей всегда выполняются в порядке abcdefghi, сколько бы вы ни перезагружали страницу. Сначала восемь импортированных модулей выполняются в порядке, указанном операторами import
с их именами. Родительский модуль i выполняется последним.
Пост-заказ обход
Теперь давайте более тщательно проверим, следует ли порядок выполнения модуля JavaScript обходу пост-порядка слева направо. Я добавил import
операторов к восьми модулям выше, чтобы воспроизвести дерево зависимостей, показанное на иллюстрации вверху.
Теперь модуль f является корневым-родительским для всех оставшихся модулей в дереве зависимостей. Он будет запущен из браузера.
import './b.js'; import './g.js'; recordExecution(import.meta.url); const order=exections.join(''); console.assert(order==='acedbhigf',order);
модуль b:
import './a.js'; import './d.js'; recordExecution(import.meta.url);
модуль g:
import './i.js'; recordExecution(import.meta.url);
модуль d:
import './c.js'; import './e.js'; recordExecution(import.meta.url);
модуль i:
import './h.js'; recordExecution(import.meta.url);
Конечные модули a, c, e, h ничего не импортируют и остаются такими же, как в предыдущем контрольная работа.
Девять модулей действительно выполняются в порядке acedbhigf, показанном на иллюстрации прохождение пост-порядка слева направо.
Влияние верхнего уровня await
на порядок выполнения модуля
Без await
модули ES6 гарантированно работают в том же детерминированном порядке. Чтобы увидеть, как await
изменяет предопределенный порядок, я вставил await
в модуль d, который одновременно является родительским и дочерним:
import './c.js'; import './e.js'; //blocks the module execution for 1 second await new Promise(resolve => setTimeout(resolve, 1000)); recordExecution(import.meta.url);
Поскольку await
блокирует выполнение d и его родительского элемента b на одну секунду (время, достаточное для выполнения оставшихся крошечных модулей), порядок должен измениться на acehigdbf.
Как и в предыдущем тесте, я проверяю порядок в корневом модуле f:
import './b.js'; import './g.js'; recordExecution(import.meta.url); const order=exections.join(''); console.assert(order==='acehigdbf',order);
Порядок действительно всегда acehigdbf.