Асинхронная загрузка файлов js для оптимизации производительности веб-страницы

внешний интерфейс JavaScript браузер HTML

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

Браузер загружает скрипт JavaScript, в основном через<script>Элемент завершен. Обычный процесс загрузки страницы выглядит так.

  1. Браузер начинает синтаксический анализ HTML-страницы по мере ее загрузки. То есть он не ждет, пока загрузка завершится, а затем начинает синтаксический анализ.
  2. В процессе парсинга браузер находит<script>элемент, приостановить синтаксический анализ и передать управление рендерингом веб-страницы движку JavaScript.
  3. если<script>Если элемент ссылается на внешний скрипт, загрузите скрипт и выполните его, в противном случае выполните код напрямую.
  4. После выполнения механизма JavaScript управление возвращается механизму рендеринга, чтобы возобновить синтаксический анализ HTML-страниц.

При загрузке внешнего скрипта браузер приостановит отрисовку страницы, дождется загрузки и выполнения скрипта, а затем продолжит отрисовку. Причина в том, что код JavaScript может модифицировать DOM, поэтому управление должно быть передано ему, иначе это приведет к сложным проблемам гонки потоков.

Вышеупомянутое — это то, что мы обычно видим чаще всего.<script>этикетка на<head>На практике такой способ загрузки называетсясинхронная загрузка, или блокируя загрузку, потому что при загрузке файла скрипта js браузеру будет заблокирован анализ HTML-документа, и HTML-документ не будет проанализирован до завершения загрузки и выполнения. Если время загрузки слишком велико (например, время загрузки слишком велико), это приведет к тому, что браузер «симулирует смерть», и страница будет пустой. Более того, положить<head>DOM нельзя манипулировать в файле js, загруженном синхронно в , иначе возникнет ошибка, потому что в это время HTML не проанализирован и DOM не сгенерирован. С этой точки зрения опыт синхронной загрузки часто не очень хорош.

Давайте рассмотрим несколько способов асинхронной загрузки.

  1. Буду<script>этикетка на<body>Нижний

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

    Буду<script>помещать<body>По сути, это решает несколько проблем, упомянутых выше.Во-первых, это не приведет к блокировке парсинга страницы.Даже если время загрузки слишком велико, пользователи могут видеть страницу, а не пустую, и в это время DOM может манипулировать в сценарии.

  2. deferАтрибуты

    Давая<script>Настройки ярлыкаdeferсвойство для установки файла скрипта на ленивую загрузку, когда браузер встречаетdeferатрибут<script>тег, он откроет другой поток для загрузки файла js и одновременно продолжит анализ документа HTML.После того, как весь HTML будет проанализирован и DOM загружен, загруженный файл js будет выполнен.

    Этот метод подходит только для ссылок на внешние файлы js.<script>тег, вы можете убедиться, что порядок выполнения нескольких файлов js совпадает с порядком их появления на странице, но обратите внимание на добавлениеdeferфайлы JS для свойств не должны использовать метод document.write.

  3. asyncАтрибуты

    asyncсвойства иdeferСвойства аналогичны, и будет открыт поток для загрузки файла js, но такой же, какdeferИными словами, он будет выполняться сразу после завершения загрузки, а не ждать, пока загрузится DOM, поэтому он все равно может вызвать блокировку.

    такой же,asyncОн также применим только к внешним файлам js, а метод document.write нельзя использовать в js, но для нескольких файлов сasyncjs, нельзя гарантировать, что он будет выполнен в том же порядке, что и defer, какой бы js-файл был загружен первым, он будет выполнен первым.

  4. динамически созданный<script>Этикетка

    может быть создан динамически с помощью<script>тег для асинхронной загрузки js-файлов, например следующий код:

    (function(){
        var scriptEle = document.createElement("script");
        scriptEle.type = "text/javasctipt";
        scriptEle.async = true;
        scriptEle.src = "http://cdn.bootcss.com/jquery/3.0.0-beta1/jquery.min.js";
        var x = document.getElementsByTagName("head")[0];
        x.insertBefore(scriptEle, x.firstChild); 
    })();
    

    или

    (function(){
        if(window.attachEvent){
            window.attachEvent("load", asyncLoad);
        }else{
            window.addEventListener("load", asyncLoad);
        }
        var asyncLoad = function(){
        var ga = document.createElement('script'); 
        ga.type = 'text/javascript'; 
        ga.async = true; 
        ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'; 
        var s = document.getElementsByTagName('script')[0]; 
        s.parentNode.insertBefore(ga, s);
        }
    })();
    

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

    Вот краткое описаниеwindow.DOMContentLoadedа такжеwindow.onloadРазница между этими двумя событиями заключается в том, что первое запускается после анализа DOM.При анализе DOM JavaScript может получить ссылку на DOM, но некоторые ресурсы на странице, такие как изображения, видео и т. д., не были обработаны. загружается, а функция такая же, как и в событии jQuery.ready. Последнее — когда страница загружена полностью, включая различные ресурсы.

После разговора об этих распространенных способах асинхронной загрузки js-скриптов, давайте рассмотрим последний вопрос, когда его использовать.defer, когда использоватьasyncШерстяная ткань? Вообще говоря, выбор между ними зависит от того, есть ли зависимость между сценариями, Если есть зависимость, порядок выполнения должен быть гарантирован.deferИспользовать без зависимостейasync, если использовать одновременноdeferневерный. Обратите внимание, что ни один из них не должен использовать document.write, это приведет к очистке всей страницы.

На следующем рисунке показана синхронная загрузка иdefer,asyncРазница при загрузке, где зеленая линия представляет синтаксический анализ HTML, синяя линия представляет чтение js-скрипта по сети, а красная линия представляет время выполнения js-скрипта:

同步加载、defer、async的区别