В настоящее время на этапе 3 следующая версия ECMAScript, вероятно, будет иметь возможность динамически импортировать, без блокировки, асинхронные модули.

Обоснование этого состоит в том, что, особенно в Интернете, вы можете захотеть импортировать модули по запросу, в отличие от обязательных инструментов для предварительной сборки всех ваших скриптов.

Хотя аналогичный подход, известный как AMD, исторически проигрывал битву с пакетами CommonJS, сегодня у нас есть языковые функции, такие async и await , а также более совершенные примитивы, такие как Promise, так что асинхронный импорт может быть таким же простым, как: const module = await import('./module.js');

Но как насчет асинхронного экспорта?

По той же причине у нас есть механизмы import и export для определения наших модулей, мы также можем захотеть создать модули, которые зависят от условных модулей, способных также асинхронно экспортировать свою функциональность.

Вот несколько вариантов использования этого сценария:

  • полифиллы на основе обнаружения функций, импорт произвольного количества модулей перед экспортом их функциональности.
  • Настраиваемые элементы, зависящие от других настраиваемых элементов, поскольку объединение их всех сразу делает невозможным повторное использование компонентов.
  • Пользовательские элементы также уже имеют механизм на основе обещаний, например customElements.whenDefined('comp-name').then(useIt); сочетание этого с динамическим импортом, который разрешит и зарегистрирует компоненты один раз, является наиболее естественным шагом вперед.
  • фактический экспорт функций после подключения к БД, после анализа удаленного файла, после любой асинхронной операции, необходимой для того, чтобы экспортируемый модуль пригодное для использования выполнено.

Последний пункт действительно даже не требует использования асинхронного import, это уже довольно распространенный вариант использования на стороне сервера.

Раньше на этом канале…

Я уже писал об асинхронном импорте / экспорте и сделал предложение людям CommonJS и NodeJS, и многие разработчики выступили против идеи асинхронного импорта, потому что никому это не нужно .

Если ничего не стоит, я действительно этого хочу, и, двигаясь вперед к сети за HTTP / 2 и более совершенным механизмом кеширования, подобным тому, который предоставляется Service Workers, я не вижу причин для отсутствия асинхронного экспорта.

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

Импортируемый (…) полифилл как игровая площадка

Даже если я сам заявил, что функцию import() невозможно выполнить полифилом, мне действительно удалось создать сценарий начальной загрузки размером ~ 1 КБ, способный переносить как собственные, так и транспилированные модули в браузер, внедряя во время выполнения функцию import() во всей красе. :

  • совместим с относительными, абсолютными и удаленными путями
  • совместим как со статическим, так и с динамическим импортом
  • совместим с собственным JS или транслированным кодом Babel, aka совместим со всеми старыми и современными браузерами, совместимыми с ES5

Все находится на GitHub, и чтобы начать играть с ним, вам просто нужно включить import.js script и определить атрибут data-main , указывающий на ваш основной / индексный файл JavaScript.

Также есть пара живых примеров: перенесенный, который должен быть зеленым в каждом браузере, и пример на основе встроенных функций импорта / экспорта ES2015, требующий совместимого браузера, такого как Safari в macOS или GNOME Web в любой линукс.

Существует также тестовая папка с более запутанным тестом, сравнивающим собственный импорт и синхронный импорт VS динамический, с сохранением шаблона асинхронного экспорта, который я собираюсь объяснить в следующем абзаце.

Один раз асинхронно, все асинхронно

Я обсуждал этот паттерн уже в ES-Discuss ML, и хотя есть место для вечного разговора о паттернах для динамического экспорта и / или частичного экспорта модуля, я всегда поддерживаю подходы KISS и YAGNI.

CommonJS научил нас, что ...

Наиболее распространенный шаблон для экспорта модулей в CommonJS - через module.exports = {...};

Функции, классы, объекты, все они определены как одна запись объекта модуля, что-то «повторно засахарено» в модулях ES2015 через export default {...};

Так как насчет того, чтобы экспортировать один раз асинхронно через единственную точку входа по умолчанию?

Вкратце об асинхронном экспорте JS

Поздравляем, вы узнали все, что нужно для экспорта асинхронного модуля!

Теперь давайте быстро рассмотрим функции, которые дает этот шаблон:

  • вы все еще можете статически import mod from './mod.js';на верхнем уровне, когда у вас есть синхронные зависимости
  • вы можете await anything;внутри обратного вызова обещания, включая динамические import(...), подключения к базе данных, получение удаленных URL-адресов и т. д.
  • любой потребитель модуля может использовать шаблон по мере необходимости
  • шаблон всегда работает, независимо от того, хотите ли вы импортировать или экспортировать асинхронно

Шаблон также может легко взаимодействовать с CommonJS

что, в свою очередь, означает, что он совместим даже со связанными файлами, или, в более общем смысле, этот шаблон совместим с наиболее распространенными, реальными вариантами использования модулей.

Упрощение бита «ожидание (ожидание…)»

Как ни странно, использование этого шаблона в CommonJS выглядит проще и прямолинейнее, чем собственные модули ES2015, и причина в том, что defaultexport в CommonJS всегда неявный.

Если мы не используем транспиляторы для наших модулей и нацелены на CommonJS как на модульную систему, нам ничего не нужно делать: все сборщики будут просто работать, некоторые могут даже решить сделать browserrequiresmarter и загружать асинхронно вместо объединения всех модулей: это ваш звонок.

Однако, если мы пишем код через транспиляторы, мы, вероятно, захотим упростить бит импорта, включая возможность одновременного импорта статических или нескольких динамических модулей. Все, что нужно, чтобы иметь такую ​​функциональность.

Каким бы компактным он ни казался, указанный выше модуль может упростить множество динамических операций импорта.

Перспективы и ориентированы на будущее

В том же машинном обучении, где я задавал вопросы об этом шаблоне, кто-то уже упоминал о возможности ввести export await во всех его формах, включая default.

Это означает, что в будущем даже статический импорт будет совместим с шаблоном, упомянутым в этом сообщении, и единственная разница будет заключаться в ключевом слове await между default и new Promise.

… Как насчет пользовательских элементов?

Вы правы, я их упомянул, но не привел ни одного конкретного примера, так что вот и я.