Такая беспечность в выполнении кода довольно удивительна, но важно понимать, что сценарии, отмеченные как async, не всегда будут запускаться по порядку. Может случиться, что несколько таких сценариев будут запущены в последовательности, отличной от указанной в разметке. Точно известно лишь то, что сценарии с async начнут выполнение в некоей загадочной точке до срабатывания события load.
defer
Атрибут defer несколько отличен от async:
<script defer src="someRandomScript.js"></script>
Сценарии, помеченные defer, запускаются в том порядке, в каком были определены, но выполняются только в самом конце, за несколько мгновений до срабатывания события DOMContentLoaded. Взгляните на следующий пример:
<!DOCTYPE html>
<html>
<body>
<h1>Example</h1>
<script defer src="external1.js"></script>
<script>
console.log("inline 1");
</script>
<script src="external2.js"></script>
<script>
console.log("inline 2");
</script>
<script defer src="external3.js"></script>
<script>
console.log("inline 3");
</script>
</body>
</html>
Задумайтесь на секунду и расскажите находящемуся рядом человеку (или животному), в каком порядке эти сценарии будут запущены. При этом можете не пояснять контекст, ведь если они вас любят, то обязательно поймут.
Запустятся они в такой последовательности: inline 1, external 2, inline 2, inline 3, external 3, а затем external 1. Сценарии external 3 и external 1 помечены как defer, именно поэтому они оказываются в конце, несмотря на свое положение в разметке.
КОРОТКО О ГЛАВНОМ
В последних разделах мы рассмотрели факторы, влияющие на время запуска кода. Схема ниже объединяет весь этот материал:
Теперь перейдем к актуальному для вас вопросу. Какое время будет наилучшим для выполнения вашего кода JavaScript? Важно добиться следующего:
1. Ссылки на сценарии располагайте ниже DOM, сразу над закрывающим body элементом.
2. Если вы не создаете библиотеку для других пользователей, не усложняйте код прослушиванием событий DOMContentLoaded или load. Прочтите предыдущий пункт.
3. Помечайте сценарии, ссылающиеся на внешние файлы, атрибутом defer.
4. Если у вас есть код, не зависящий от загрузки DOM и выполняемый как часть разветвления других сценариев в документе, его можно поместить вверх страницы, снабдив атрибутом async.
Вот и все. Думаю, что этих четырех рекомендаций хватит, чтобы в 90 % случаев обеспечить своевременный запуск кода. Для более продвинутых сценариев следует рассмотреть сторонние библиотеки вроде require.js, которые дают больший контроль над временем запуска кода. Если у вас возникнут какие-либо сложности с загрузкой, обращайтесь на https://forum.kirupa.com.
Дополнительные ресурсы и примеры:
• Загрузка модулей с помощью RequireJS: http://bit.ly/kirupaRequireJS
• Предварительная загрузка изображений: http://bit.ly/kirupaPreloadImages
Глава 36. Обработка событий для нескольких элементов
Базово слушатель событий работает с событиями, запускаемыми одним элементом:
Однако по мере создания более сложных программ отображение «одного обработчика событий для одного элемента» уже не подойдет. Причина в динамическом создании элементов посредством JavaScript. Эти элементы могут запускать события, которые вам может понадобиться прослушать и на которые соответственно среагировать. При этом вам может потребоваться обработка событий как для нескольких элементов, так и для их множества.
Вряд ли вы захотите делать так:
Вам не захочется создавать слушателя событий для каждого элемента, если слушатель событий для всех них одинаков. Причина в том, что это непродуктивно. Каждый из этих элементов несет в себе данные об одном и том же слушателе событий и его свойствах, что может существенно увеличить потребление памяти при добавлении большого количества содержимого. Вам, наоборот, нужен чистый и быстрый способ обработки событий для множества элементов с минимальным количеством повторений и ненужных компонентов. Предпочтительный вариант в этом случае будет выглядеть примерно так:
Все это может звучать несколько нереально, не так ли? Что ж, в этой главе вы узнаете, что это вполне нормально, и научитесь реализовывать подобное, используя всего несколько строк кода JavaScript.