en.javascript.info/1-js/2-first-steps/2-external-script/article.md
2015-04-14 11:02:21 +03:00

11 KiB
Raw Blame History

Внешние скрипты, порядок исполнения

Если JavaScript-кода много -- его выносят в отдельный файл, который подключается в HTML:

<script src="/path/to/script.js"></script>

Здесь /path/to/script.js -- это абсолютный путь к файлу, содержащему скрипт (из корня сайта).

Браузер сам скачает скрипт и выполнит.

Можно указать и полный URL, например:

<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.2.0/lodash.js"></script>

Вы также можете использовать путь относительно текущей страницы, например src="lodash.js" обозначает файл из текущей директории.

Чтобы подключить несколько скриптов, используйте несколько тегов:

<script src="/js/script1.js"></script>
<script src="/js/script2.js"></script>
...

[smart] Как правило, в HTML пишут только самые простые скрипты, а сложные выносят в отдельный файл.

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

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

[/smart]

[warn header="Если указан атрибут src, то содержимое тега игнорируется."]

В одном теге SCRIPT нельзя одновременно подключить внешний скрипт и указать код.

Вот так не cработает:

<script *!*src*/!*="file.js">
  alert(1); // так как указан src, то внутренняя часть тега игнорируется
</script>

Нужно выбрать: либо SCRIPT идёт с src, либо содержит код. Тег выше следует разбить на два: один -- с src, другой -- с кодом, вот так:

<script src="file.js"></script>
<script>
  alert( 1 );
</script>

[/warn]

Асинхронные скрипты: defer/async

Обычно тег <script> блокирует отображение страницы.

Например, в примере ниже -- пока все кролики не будут посчитаны -- нижний <p> не будет показан:

<!--+ run height=100 -->
<!DOCTYPE HTML>
<html>

<head>
  <meta charset="utf-8">
</head>

<body>

  <p>Начинаем считать:</p>

*!*
  <script>
    alert( 'Первый кролик!' );
    alert( 'Второй кролик!' );
    alert( 'Третий кролик!' );
  </script>
*/!*

  <p>Кролики посчитаны!</p>

</body>

</html>

Такое поведение называют "синхронным". Как правило, оно вполне нормально, но есть один нюанс.

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

В ряде случаев это совсем неуместно. Например, мы подключаем внешний скрипт, который показывает рекламу или вставляет счётчик посещений, а затем идёт наша страница. Конечно, неправильно, что пока счётчик или реклама не подгрузятся -- оставшаяся часть страницы не показывается. Счётчик посещений не должен никак задерживать отображение страницы сайта. Реклама -- это дополнение к странице, она не должна как-то тормозить сайт и нарушать его функционал.

А что, если сервер, с которого загружается внешний скрипт, перегружен? Посетитель в этом случае может ждать очень долго.

Вот пример, с подобным скриптом (стоит искусственная задержка загрузки):

<!--+ run height=100 -->
<p>Начало страницы...</p>

<script src="https://js.cx/hello/ads.js?speed=0"></script>

<p>...Важная информация!</p>

В примере выше важная информация не покажется, пока не загрузится внешний скрипт. Но действительно ли он так важен, что мы хотим заставить посетителя ждать? Если это реклама или счётчик посещаемости, то вряд ли.

Можно поставить все подобные скрипты в конец страницы -- это уменьшит проблему, но не избавит от неё полностью, поскольку скриптов может быть несколько, и если какой-то один скрипт тормозит или завис, то последующие будут его ждать.

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

Кардинально решить эту проблему помогут атрибуты async или defer:

Атрибут `async`
Поддерживается всеми браузерами, кроме IE9-. Скрипт выполняется полностью асинхронно. То есть, при обнаружении ``
  • Специальные атрибуты `async` и `defer` используются для того, чтобы пока грузится внешний скрипт -- браузер показал остальную (следующую за ним) часть страницы. Без них этого не происходит.
  • Разница между `async` и `defer`: атрибут `defer` сохраняет относительную последовательность скриптов, а `async` -- нет.
  • Очень важно не только читать учебник, но делать что-то самостоятельно.

    Решите задачки, чтобы удостовериться, что вы все правильно поняли.