Предисловие
Независимо от того, встроен ли текущий код JavaScript или во внешнем файле ссылки, загрузка и рендеринг страницы должны быть остановлены и ждать выполнения сценария. Чем дольше процесс выполнения JavaScript, тем дольше браузер ждет ответа на пользовательский ввод. Причина, по которой браузеры блокируют при загрузке и выполнении сценариев, заключается в том, что сценарии могут изменить пространство имен страницы или JavaScript, что влияет на содержание последующих страниц. Типичным примером является использование document.write() на странице, например, в листинге 1
Перечисление 1 встроенного примера кода JavaScript
<html> <Head> <Title> Пример исходного исходного </title> </head> <body> <p> <script type = "text/javascript"> document.write ("сегодня" + (new Date ()). todatestring ()); </script> </p> </body> </html>Когда браузер встречается с тегом <script>, текущая HTML -страница не может узнать, добавит ли JavaScript контент в тег <p>, представлять другие элементы или даже удалить тег. Поэтому в настоящее время браузер перестанет обрабатывать страницу, сначала выполнит код JavaScript, а затем продолжит анализировать и отображать страницу. То же самое происходит при загрузке JavaScript с помощью свойства SRC. Браузер должен сначала потратить время, чтобы загрузить код в файле внешней ссылки, а затем разобрать и выполнить его. В течение этого процесса рендеринг страницы и взаимодействие с пользователем полностью заблокированы.
Расположение сценария
Спецификация HTML 4 гласит, что теги <Script> могут быть размещены в <head> или <body> документах HTML, и им разрешается появляться несколько раз. Веб -разработчики, как правило, привыкли загружать внешнюю ссылку JavaScript в <Head>, а затем используют тег <link> для загрузки файлов внешней ссылки CSS или другой информации страницы. Например, листинг 2
Список 2 Пример неэффективных местоположений сценариев
<html> <Head> <tite> Пример исходного исходного </title> <script type = "text/javascript" src = "script1.js"> </script> <script type = "text/javascript" src = "script2.js"> </script> <script type = "text/javascript" src = " type = "text/javascript" src = "script3.js"> </script> <link rel = "stylesheet" type = "text/css" href = "styles.css"> </Head> <body> <p> Hello World! </p> </body> </html>
Тем не менее, этот обычный подход скрывает серьезные проблемы с производительностью. В примере в списке 2, когда браузер анализирует тег <croppl> (строка 4), браузер прекращает анализ последующего контента и приоритет загрузке файла скрипта и выполняющую его код, что означает, что ни последующий файл стиля styles.css не можно загрузить. Поскольку тег <body> не может быть загружен, страница, естественно, не будет отображаться. Следовательно, страница является пустой до тех пор, пока код JavaScript не будет полностью выполнен. Рисунок 1 описывает процесс загрузки сценариев и файлов стиля во время загрузки страницы.
Рисунок 1 Загрузка и выполнение файлов JavaScript, блокирующие загрузку других файлов
Мы можем найти интересное явление: первый файл JavaScript начинает загружать, при этом блокируя загрузку других файлов на странице. Кроме того, существует задержка до того, как загрузка Script1.js завершена, и Script2.js начинает загружать, что является процессом выполнения файла script1.js. Каждый файл должен ждать, пока предыдущий файл не будет загружен и выполнен, прежде чем он сможет начать загрузку. Во время загрузки этих файлов один за другим пользователь видит пустую страницу.
Начиная с IE 8, Firefox 3.5, Safari 4 и Chrome 2, все позволяют загружать файлы JavaScript параллельно. Это хорошие новости, потому что тег <script> не блокирует другие теги <script> при загрузке внешних ресурсов. К сожалению, процесс загрузки JavaScript по -прежнему будет блокировать загрузку других ресурсов, таких как стиль файлов и изображения. Хотя процесс загрузки скрипта не влияет друг на друга, страница все еще должна ждать, пока весь код JavaScript будет загружен и выполнен, прежде чем она сможет продолжить. Таким образом, в то время как последние браузеры улучшают производительность, позволяя параллельно загружать, проблема не была полностью решена, и блокирование сценариев остается проблемой.
Поскольку сценарии блокируют загрузки других ресурсов на странице, рекомендуется разместить все теги <script> в нижней части тегов <body>, насколько это возможно, чтобы минимизировать влияние на всю загрузку страницы. Например, листинг 3
Листинг 3 примера рекомендуемого размещения кода
<html> <head> <title> Пример источника </title> <link rel = "styleSheet" type = "text/css" href = "styles.css"> </head> <body> <p> Hello World! </p> <!-Пример позиционирования эффективного сценария-> <Script Type = "javascript" src = "script1. type = "text/javascript" src = "script2.js"> </script> src = "script3.js"> </script> </body> </html>
Этот код показывает рекомендуемое место для размещения <script> тегов в документах HTML. Хотя загрузки сценариев блокируют другой сценарий, большая часть страницы была загружена и отображена на пользователь, поэтому загрузка страницы не будет выглядеть слишком медленной. Это первое правило для оптимизации JavaScript: положите сценарий внизу.
Организуйте сценарии
Поскольку каждый тег <Script> заблокирован, когда страница изначально загружается, уменьшение количества тегов <croppl>, включенных на страницу, помогает улучшить эту ситуацию. Это не только для сценариев внешней ссылки, но и для количества встроенных сценариев. Всякий раз, когда браузер сталкивается с тегом <script> во время анализа HTML -страницы, он вызовет определенную задержку из -за выполнения сценария, поэтому минимизация времени задержки значительно улучшит общую производительность страницы.
Эта проблема немного отличается при работе с внешними файлами JavaScript. Учитывая дополнительные накладные расходы HTTP -запросов HTTP, загрузка одного файла 100 КБ будет быстрее, чем загрузка 5 20 КБ файлов. То есть сокращение количества сценариев внешней ссылки на странице улучшит производительность.
Обычно крупный веб -сайт или приложение должны полагаться на несколько файлов JavaScript. Вы можете объединить несколько файлов в один, чтобы вам нужно было только ссылаться на тег <croppling>, чтобы уменьшить потребление производительности. Слияние файлов может быть достигнуто с помощью автономных инструментов упаковки или некоторых онлайн-сервисов в реальном времени.
Следует отметить, что размещение встроенного сценария после ссылки на лист стиля внешней ссылки приведет к тому, что страница будет заблокировать и ждать загрузки листа стиля. Это сделано для того, чтобы встроенные сценарии могли получить наиболее точную информацию о стиле при выполнении. Следовательно, рекомендуется не следовать встроенным сценариям сразу после тега <NINK>.
Не блокирующие сценарии
Сокращение размера файла JavaScript и ограничение HTTP-запросов не всегда осуществляется на богатых функциях веб-приложения или большие веб-сайты. Чем больше функций является веб -приложением, тем больше кода JavaScript он нуждается. Несмотря на то, что загрузка одного большего файла JavaScript генерирует HTTP -запрос только один раз, он долго заблокирует браузер. Чтобы избежать этого, необходимо постепенно загружать файлы JavaScript в страницу с помощью некоторых конкретных методов, так что в некоторой степени он не блокирует браузер.
Секрет разблокировки сценариев заключается в том, что код JavaScript загружается только после загрузки страницы. Это означает загрузку сценария после того, как нагрузка Ondow Object будет запущено. Есть ряд способов достичь этого эффекта.
Задержка загрузки сценариев
HTML 4 определяет расширенный атрибут для тега <Script>: defer. Атрибут DEFE указывает, что сценарий, содержащийся в этом элементе, не изменяет DOM, поэтому код может быть безопасно отсрочен. Атрибут Defer поддерживается только IE 4 и Firefox 3.5 более поздними браузерами, поэтому он не является идеальным решением поперечного браузера. В других браузерах атрибут Defer игнорируется напрямую, поэтому тег <croppl> будет обрабатываться по умолчанию, что означает, что он вызовет блокировку. Тем не менее, это все еще полезное решение, если ваш целевой браузер поддерживает его. Листинг 4 является примером
Список 4 примера метода использования атрибутов DEFE
<script type = "text/javascript" src = "script1.js" defer> </script>
Тег <cript> с атрибутом Defer может быть размещен в любом месте в документе. Соответствующий файл JavaScript начнет загрузку, когда страница будет проанализирована к тегу <Script>, но не будет выполнена до тех пор, пока не будет загружен DOM, то есть событие Onload не будет запущено. Когда файл JavaScript с атрибутом Defer загружается, он не блокирует другие процессы в браузере, поэтому такие файлы можно загрузить параллельно с другими файлами ресурсов.
Любой элемент <script> с атрибутом Defer не будет выполняться до тех пор, пока не будет загружен DOM, будь то встроенные или внешние сценарии. Пример в списке 5 показывает, как атрибут DEFE влияет на поведение скрипта:
Список 5 Влияние атрибута DEFE на поведение скрипта
<html> <Head> <Title> Пример отложения скрипта </title> </head> <body> <script type = "text/javascript" defer> alert ("defer"); </script> <script type = "text/javascript"> alert ("script"); </script> <script type = "text/javascript"> window.onload = function () {alert ("загрузка"); }; </script> </body> </html>Этот код появляется три диалоговых окна при обработке страниц. Всплывающий порядок браузеров, которые не поддерживают атрибут Defer: «DEFER», «Script» и «Load». В браузерах, которые поддерживают атрибут DEFE, всплывающий заказ: «Скрипт», «DEFER» и «LOAD». Обратите внимание, что элемент <script> с атрибутом Defer не выполняется после второго, но вызван до запуска события Onload.
Если ваш целевой браузер включает только Internet Explorer и Firefox 3.5, сценарий DEFE действительно полезен. Если вам нужно поддерживать несколько браузеров в разных доменах, существуют более последовательные способы его реализации.
HTML 5 определяет новый расширенный атрибут для тега <Script>: async. Его функция такая же, как отсрочка, и он может загружать и выполнять сценарии асинхронно, не блокируя загрузку страницы из -за загрузки сценариев. Тем не менее, что следует отметить, что в случае асинхронности сценарии JavaScript будут выполнены после их загрузки, поэтому вполне вероятно, что они не выполняются в исходном порядке. Если существуют зависимости до и после сценариев JavaScript, очень вероятно, что ошибка возникнет с использованием Async.
Динамические элементы сценария
Модель объекта документа (DOM) позволяет динамически создавать практически все содержание документа HTML с помощью JavaScript. Элемент <Script>, как и другие элементы страницы, может быть создан очень легко со стандартными функциями DOM:
Листинг 6 Создание <cript> элементы со стандартными функциями DOM
var script = document.createElement ("script"); script.type = "text/javascript"; script.src = "script1.js"; document.getElementsbytagname ("head") [0] .appendchild (script);Новый элемент <Script> загружает исходный файл Script1.js. Загрузите этот файл сразу после добавления элемента на страницу. Ключевой момент этой технологии заключается в том, что независимо от того, с чего начинается загрузка, загрузка и запуск файла не заблокируют другие страницы. Вы даже можете поместить эти коды в разделе <head>, не влияя на код страницы для остальных (за исключением подключений HTTP, используемых для загрузки файлов).
Когда файл загружается с использованием узла динамического скрипта, возвращаемый код обычно выполняется немедленно (кроме Firefox и Opera, они будут ждать всех предыдущих узлов динамических сценариев для завершения выполнения). Этот механизм работает нормально, когда сценарий имеет «самостоятельный» тип, но если сценарий содержит только интерфейсы для вызова других сценариев на странице, это вызовет проблемы. В этом случае вам нужно отслеживать, будет ли загрузка сценария завершена и готова ли он. Вы можете использовать Dynamic <croppling> узлы для выпуска событий для получения соответствующей информации.
Firefox, Opera, Chorme и Safari 3+ выпустит событие Onload после завершения приема узел <Script>. Вы можете послушать это событие, чтобы получить уведомления, подготовленные сценарием:
Перечисление 7 загрузки сценариев JavaScript, прослушивая события Onload
var script = document.createElement ("script") script.type = "text/javascript"; // Firefox, Opera, Chrome, Safari 3+script.onload = function () {alert ("Скрипт загружен!");}; script.src = "script1.js"; document.getElementsbytagname ("head") [0] .appendChild (script);Internet Explorer поддерживает еще одну реализацию, которая издает событие BetowerstateChange. Элемент <Script> имеет свойство готового участка, значение которого изменяется как процесс загрузки внешних файлов. Есть пять значений для готового участка:
1.
2. "Загрузка": загрузка начинается
3. "Загружен": загрузка завершена
4. "Interactive": загрузка завершена, но еще не доступна
5. «Полное»: все данные готовы
В документации Microsoft говорится, что в течение жизненного цикла элемента <Script> эти значения reatestate не могут появиться, но не указывают, какие значения всегда будут использоваться. На практике нас больше всего интересует «загруженные» и «полные» состояния. Internet Explorer не имеет окончательного состояния, представленного этими двумя ценностями готовых статей. Иногда элемент <Script> получает «загрузчик», но никогда не «завершается», но в некоторых случаях «завершен» появляется и «загружен» не может быть использован. Самый безопасный способ - проверить эти два состояния в событии BeadyStateChange, и когда появится одно из состояний, удалите рукоятку событий BeadyStateChange (убедитесь, что событие не будет обработано дважды):
Перечисление 8 загрузки сценариев JavaScript путем проверки статуса готового штата
var script = document.createElement ("script") script.type = "text/javascript"; // Internet explorerscript.OnreadyStateChange = function () {if (script.ReadyState == "загружен" оповещение («Скрипт загружен»); }}; script.src = "script1.js"; document.getelementsbytagname ("head") [0] .appendchild (script);В большинстве случаев вы хотите вызвать функцию для реализации динамической загрузки файлов JavaScript. Следующие функции инкапсулируют функции, требуемые стандартными реализациями и реализациями IE:
Листинг 9 инкапсуляции по функции
function loadscript (url, обратный вызов) {var script = document.createElement ("script") script.type = "text/javascript"; if (script.readystate) {// ie script.onreadystatechange = function () {if (script.readystate == "загружен" перезвонить(); }}; } else {// other script.onload = function () {callback (); }; } script.src = url; document.getElementsbytagname ("head") [0] .appendchild (script);}Эта функция получает два параметра: URL -адрес файла JavaScript и функцию обратного вызова, которая запускается при завершении приема JavaScript. Проверка атрибутов используется для определения того, какое событие для мониторинга. На последнем этапе установите свойство SRC и добавьте элемент <Script> на страницу. Эта функция loadscript () используется следующим образом:
Листинг 10 Как использовать функцию loadscript ()
loadscript ("script1.js", function () {alert ("файл загружен!");});Вы можете динамически загружать много файлов JavaScript на странице, но будьте осторожны, чтобы браузер не гарантировал порядок, в котором файлы загружаются. Среди всех основных браузеров только Firefox и Opera гарантируют, что сценарии выполняются в указанном вами заказе. Другие браузеры будут загружать и запускать разные кодовые файлы в том порядке, когда сервер возвращает их. Вы можете объединить операции загрузки вместе, чтобы обеспечить их заказ следующим образом:
Перечисление 11 Загрузить несколько сценариев JavaScript через функцию loadScript ()
loadscript ("script1.js", function () {loadscript ("script2.js", function () {loadscript ("script3.js", function () {alert ("Все файлы загружаются!");});});}); });Этот код ждет, пока Script1.js будет доступен до начала загрузки script2.js, а затем начнет загружать Script3.js после Script2.js. Хотя этот метод возможен, он все еще немного хлопотно, если есть много файлов для загрузки и выполнения. Если порядок нескольких файлов очень важен, лучшим способом является подключение файлов в один файл в правильном порядке. Автономный файл может загружать весь код одновременно (поскольку это делается асинхронно, в использовании большого файла нет потерь).
Динамическая загрузка скрипта является наиболее часто используемым шаблоном в неблокирующих загрузках JavaScript, потому что он может быть междорным и легко использовать.
Использование объекта xmlhttprequest (xhr)
Этот метод сначала создает объект XHR, затем загружает файл JavaScript, а затем вводит код JavaScript в страницу динамическим элементом <cropript>. Список 12 - простой пример:
Список 12 загрузки сценариев JavaScript через объекты XHR
var xhr = new xmlhttprequest (); xhr.open ("get", "script1.js", true); xhr.onreadystatechange = function () {if (xhr.readystate == 4) {if (xhr.status> = 200 && xhr.status <300 | xhr.status> = 200 && xhr.status <300 | xhr.status> = 200 && xhr.status <300 | document.createElement ("script"); script.type = "text/javascript"; script.text = xhr.responsetext; document.body.appendchild (script); }}}; xhr.send (null);Этот код отправляет запрос GET на сервер, чтобы получить файл script1.js. Обработчик событий OnreadyStateChange проверяет, является ли readystate 4, а затем проверяет, действителен ли код состояния HTTP (2xx означает действительный ответ, 304 означает кэшированный ответ). Если получен допустимый ответ, создается новый элемент <script>, и его текстовый атрибут устанавливается на строку ответа, полученная с сервера. Это фактически создаст элемент <script> с встроенным кодом. После того, как новый элемент <script> добавлен в документ, код будет выполнен и готов к использованию.
Основным преимуществом этого подхода является то, что вы можете загрузить код JavaScript, который не выполняется немедленно. Поскольку код возвращается за пределы тега <cropript> (другими словами, он не подчиняется тегу <Script>), он не будет выполняться автоматически после загрузки, что позволяет вам откладывать выполнение, пока все не будет готово. Другое преимущество заключается в том, что тот же код не бросает исключения во всех современных браузерах.
Основным ограничением этого метода является то, что файлы JavaScript должны быть размещены в том же домене, что и на странице, и не могут быть загружены из CDN (CDN относится к «сети доставки контента», поэтому большие веб -страницы обычно не используют технологию впрыска сценария XHR.
Добавьте некоторые функции, которые вы обычно используете
function loadjs (url, обратный вызов, charset) {var head = document.getElementsbytagname ("head") [0]; var script = document.createElement ("script"); if (!! charset) script.charset = "utf-8"; script.src = url; script.onload = script.onreadystatechange = function () {var f = script.readystate; if (f && f! = "загружен" && f! = "overse") return; script.onload = script.onreadystatechange = null; Head.RemoveChild (Script) if (обратный вызов) {callback () || перезвонить }; }; Head.AppendChild (Script);} // JS синхронная функция загрузки GetScripts (i, Linkarray, Fn) {env || getenv (); var script = document.createElement ('script'); script.type = 'text/javascript'; script.src = linkarray [i]; var head = document.head || document.getElementsbytagname ('head') [0]; Head.AppendChild (Script); if (env.ie && 'onreadystateChange' в Script &&! ('Draggable' в Script)) {// IE Browser загружает script.onreadystatechange = function () {if (/uducted|cplete/.test(script.readyState)) {script.onReadySteChange = null; if (i === linkarray.length-1) {if (fn) {fn (); }} else {getscripts (++ i, linkarray, fn); }}}}; } else {script.onload = function () {if (i === linkarray.length-1) {if (fn) {fn (); }} else {getscripts (++ i, linkarray, fn); }}}; }} // JS имеет загрузку зависимости getscripts (0, ['http://caibaojian.com/demo/base.js', 'http://caibaojian.com/demo/reset.js'], function () {alert ('callback');});Суммировать
Есть несколько способов снизить влияние JavaScript на производительность:
Размещение всех тегов <Script> внизу страницы, то есть до закрытия тега, это гарантирует, что страница была отображена до выполнения сценария.
Слияние сценариев как можно больше. Чем меньше тегов <Script> на странице, тем быстрее он загрузится, и тем быстрее он будет отвечать. Это верно как для внешних сценариев, так и для встроенных сценариев.
Используйте разблокированные сценарии JavaScript для загрузки:
Используйте атрибут DEFE of the <Script> Tag (доступный только для IE и Firefox 3.5 или выше);
Используйте динамически созданные <script> элементы для загрузки и выполнения кода;
Используйте объекты XHR, чтобы загрузить код JavaScript и введите его на страницу.
Вышеуказанные стратегии могут значительно улучшить фактическую производительность веб -сайтов и приложений, которые требуют большого количества JavaScript.
Выше приведено полное содержание резюме оптимизации производительности JavaScript. Загрузка и выполнение. Я надеюсь, что это будет полезно для всех.