Что происходит, когда скрипт загружается как «preload» / «modulepreload»?

Sep 06 2020

На web.dev есть очень интересная статья о модульном работнике https://web.dev/module-workers/ где у нас есть возможность загрузить воркера как предварительно загруженный модуль, что означает, что они могут быть предварительно загружены и даже предварительно проанализированы и предварительно загружены их зависимости (https://web.dev/module-workers/#preload-workers-with-modulepreload).

Если я прав, не только веб-воркеры могут быть загружены как модуль предварительной загрузки, это применимо к любому js-скрипту, шрифту, CSS и т. Д., Например

<link rel="preload" href="fonts/cicle_fina-webfont.woff2" as="font" type="font/woff2" crossorigin="anonymous">

<link rel="preload" href="style.css" as="style">
<link rel="preload" href="main.js" as="script">

В этой статье есть высказывание , которое меня сильно беспокоит:

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

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

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

Я действительно не понимаю, что именно пытается объяснить автор. И как это реализовать.

Статьи по Теме: https://developers.google.com/web/updates/2017/12/modulepreload#does_preloading_modules_help_performance

Ответы

Kaiido Sep 12 2020 at 10:28

Я не уверен, откуда эта статья взяла эту идею, но, читая спецификации, я не вижу доказательств того, что

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


Если мы проверим спецификации, алгоритм выборки и обработки связанных ресурсов для modulepreloadссылок выполняется на шаге 5.

  1. Пусть объект настроек будет соответствующим объектом настроекlink документа узла элемента .

Затем этот объект настроек передается на шаге 11 для извлечения алгоритма графа скрипта модуля предварительной загрузки модуля , который сам будет вызывать извлечение скрипта одного модуля и извлекать потомков и ссылку - что в конечном итоге также вызовет выборку скрипта одного модуля - с тем же объект настроек .

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

  1. Пусть moduleMap быть настройки карты модуля объекта «s карты модуля .

  2. Если moduleMap [url] равен "fetching", дождитесь, пока значение этой записи не изменится, затем поставьте задачу в очередь в источнике сетевой задачи, чтобы продолжить выполнение следующих шагов.

  3. Если moduleMap [url] существует, асинхронно завершите этот алгоритм с moduleMap [url] и вернитесь.

Вероятно, следует отметить, что пока этот алгоритм создает скрипт модуля , он еще не выполняет его.


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

Однако этого недостаточно, чтобы сделать вывод относительно проблемной цитаты.

Мы должны проверить спецификации выделенного конструктора Workers , который вызовет запуск алгоритма worker , передавая тот же параметр объекта документа, который использовался нашей modulepreloadссылкой, на этот раз называемый « внешними настройками ».

На шаге 8 запустите рабочий алгоритм, он просит

  1. Настройте объект настроек рабочей среды с контекстом выполнения области и внешними настройками , и пусть внутренние настройки будут результатом.

И этот набор до объекта рабочи параметров среды алгоритма будет использовать только документ за пределы настройки , чтобы установить inherited originвнутреннее значение и новые настройки объект «s top-level originсвойства.

Эти новые параметры объекта «s карта модуль является одним из его глобального масштаба , что„ изначально пустой “.

Объект настроек рабочей среды не наследует карту модуля из внешних настроек .

Поэтому , когда работник сам будет называть эти выборки одного сценария модуля и извлечения потомков и ссылок алгоритмов в рамках выборки графа сценария модуль уборщица , то один модуль карта будет проверять это его собственные параметры внутри «ы модуля карты и там, он не найдет скрипты модуля modulepreload, созданные по нашей ссылке.


Итак, прочитав спецификации, я бы сказал, что modulepreloadссылки помогают только рабочим модулям, так как HTTP-кеш уже загрузил все файлы на графике. Если вы собираетесь использовать эти модули только в Worker, то подготовка скриптов модуля на стороне документа на самом деле контрпродуктивна, и простая prefetchссылка может оказаться лучше, за исключением того, что вам придется создавать одну такую ​​ссылку для каждого подресурс.

Dolly Sep 16 2020 at 23:59

Кайидо Спасибо за подробный ответ. Это очень полезно.

Я также много искал эту проблемную цитату, а затем я инициировал проблему в web.dev, если они могут обновить контент. Вы можете отслеживать по проблеме

Одна из самых сложных задач для JS Engine - это синтаксический анализ / компиляция ( что такое синтаксический анализ / компиляция ) нашего кода, и он играет важную роль во времени для взаимодействия с веб-страницей, а также есть много способов, с помощью которых мы можем улучшить TTI, например, отправив только код, необходимый пользователю ( разделение кода на веб-пакеты, фрагменты и т. д.), минификация, встряхивание дерева, http-кеширование , рабочие модули и т. д., а также не забывать предварительную загрузку

Фактическое определение предварительной нагрузки:

Основной способ использования предварительной загрузки - это ранняя загрузка поздно обнаруженных ресурсов. Хотя большинство ресурсов на основе разметки обнаруживаются предварительным загрузчиком браузера довольно рано, не все ресурсы основаны на разметке. Некоторые ресурсы скрыты в CSS и JavaScript, и браузер не может знать, что они ему понадобятся, пока не станет уже довольно поздно. Таким образом, во многих случаях эти ресурсы в конечном итоге задерживают первый рендеринг, рендеринг текста или загрузку критических частей страницы.

Коротко:

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

Раньше, если мы внедряем скрипт в тот момент, когда мы хотим, чтобы он запускался, браузер должен затем загрузить скрипт, прежде чем он сможет быть выполнен (ПРИМЕЧАНИЕ: браузер должен сделать много вещей перед выполнением вашего кода), что может занять в то время как. Но Preload решает эту проблему.

Я считаю, что автор пытается объяснить то же самое, то есть предварительно загруженные и даже предварительно проанализированные модули (не выполнять + скомпилированный байт-код кэшируется), используя тег link rel = "modulepreload" для последующей оценки (повторную компиляцию можно пропустить).

И, наконец, я считаю, что мои вопросы решены. Спасибо огромное!

Пара полезных ссылок:

  • https://developers.google.com/web/updates/2017/12/modulepreload
  • https://3perf.com/blog/link-rels/