Сейчас 2016 год, и если вы не используете теги разблокировки async и defer в JavaScript на стороне клиента, вам необходимо вмешаться.

Если присутствует атрибут async, то сценарий будет извлекаться параллельно синтаксическому анализу и оцениваться, как только он станет доступен (возможно, до завершения синтаксического анализа).

Если атрибут async отсутствует, но присутствует атрибут defer, то классический скрипт будет извлекаться параллельно и оцениваться, когда страница завершит синтаксический анализ.

Источник: WHATWG

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

Одно из наиболее очевидных применений этого метода - загрузка карт Google. Нужно ли нам, чтобы наша DOM ожидала рендеринга, пока Google Maps не будет загружен и запущен? В большинстве случаев ответ - нет.

  • Итак, какой тег мы используем? defer или async? или оба?
  • Как и где мы пишем функцию инициализации карты?

Обычная (блокирующая) реализация Google Maps будет выглядеть примерно так:

<script src="https://maps.googleapis.com/maps/api/js"></script>
...
<script>
function initMap() {
  var map = new google.maps.Map(document.getElementById('map'), {
    center: {lat: -34.397, lng: 150.644},
    zoom: 8
  });
}
google.maps.event.addDomListener(window, 'load', initMap);
</script>

Мы делаем здесь два изменения:

Добавьте async и defer в тег скрипта

<script src="https://maps.googleapis.com/maps/api/js" async defer></script>

Мы добавляем оба, потому что async поддерживается не всеми браузерами, а defer служит альтернативой для этих старых браузеров.

Если присутствует async, то скрипт будет выполнен, как только станет доступен, но без блокировки дальнейшего разбора страницы. Если async отсутствует, а defer есть, то скрипт выполняется после завершения анализа страницы.

Запускать функцию initMap при обратном вызове

<script>
function initMap() {
  var map = new google.maps.Map(document.getElementById('map'), {
    center: {lat: -34.397, lng: 150.644},
    zoom: 8
  });
}
</script>
<script src="https://maps.googleapis.com/maps/api/js?callback=initMap" async defer></script>

Обратите внимание, что тег src ‹script› изменен и теперь включает обратный вызов .

Это позволяет вызывать функцию initMap немедленно после загрузки скрипта Maps.

Тег ‹script› перемещен под функцию initMap, чтобы API Карт не мог вызывать его до его инициализации.

Представление

Синхронизировать

DOMContentLoaded запускается через ~ 600 мс (658 мс на снимке экрана ниже), а настройка карты может начинаться примерно с 700–1000 мс.

Асинхронный

DOMContentLoaded запускается через 35 мс, а настройка карты может начинаться примерно через 300–500 мс.

Попался

Поскольку теги сценария больше не загружаются синхронно в предсказуемом порядке, любой код, использующий пространство имен google.maps, должен выполняться в рамках обратного вызова или когда-нибудь позже.

Чтобы обойти это ограничение, вы можете либо вернуться к синхронной загрузке API, либо смешать свой код с родительским классом, когда он станет доступен. Если вы выбрали синхронную загрузку, вы все равно можете переместить тег ‹script› в конец раздела ‹body›, чтобы ваша страница отображалась быстро.

Вы должны обратить внимание на 2 конкретных случая:

  • Создание подклассов в Google Maps JavaScript API (например, пользовательские наложения). Вы должны убедиться, что ваши классы определены после выполнения обратного вызова.
  • LatLngs определяется вне функции инициализации карты. Большинство функций теперь принимают LatLngLiterals, поэтому вы можете просто передать {lat: 33, lng: 151}.

Удачного кодирования!