Выбрать главу

/*@cc_on @*/

/*@if (@_win32)

document.write("<script id=\"__ie_onload\" defer=\"defer\" src=\"javascript:void(0)\">

<\/script>");

var script = document.getElementById("__ie_onload");

script.onreadystatechange = function() {

if (this.readyState == "complete") {

init(); // вызываем обработчик для onload

}

};

/*@end @*/

И для Safari!

if (/WebKit/i.test(navigator.userAgent)) { // условие для Safari

var _timer = setInterval(function() {

if (/loaded|complete/.test(document.readyState)) {

clearInterval(_timer);

init(); // вызываем обработчик для onload

}

}, 10);

}

Полное решение

function init() {

// выходим, если функция уже выполнялась

if (arguments.callee.done) return;

// устанавливаем флаг, чтобы функция не исполнялась дважды

arguments.callee.done = true;

// что-нибудь делаем

};

/* для Mozilla/Firefox/Opera 9 */

if (document.addEventListener) {

document.addEventListener("DOMContentLoaded", init, false);

}

/* для Internet Explorer */

/*@cc_on @*/

/*@if (@_win32)

document.write("<script id=\"__ie_onload\"

defer=\"defer\" src=\"javascript:void(0)\">

<\/script>");

var script = document.getElementById("__ie_onload");

script.onreadystatechange = function() {

if (this.readyState == "complete") {

init(); // вызываем обработчик для onload

}

};

/*@end @*/

/* для Safari */

if (/WebKit/i.test(navigator.userAgent)) { // условие для Safari

var _timer = setInterval(function() {

if (/loaded|complete/.test(document.readyState)) {

clearInterval(_timer);

init(); // вызываем обработчик для onload

}

}, 10);

}

/* для остальных браузеров */

window.onload = init;

Неблокирующая загрузка JavaScript

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

Давайте сначала рассмотрим, в чем заключается проблема с загрузкой скриптов. Все сводится к тому, что браузер не может сказать, что находится внутри скрипта, не загрузив его полностью. Скрипт может содержать вызовы document.write(), которые изменяют DOM-дерево, или вообще location.href, что отправит пользователя на другую страницу. В последнем случае все компоненты, загруженные на предыдущей странице, могут оказаться ненужными. Чтобы предотвратить загрузки, которые могут оказаться лишними, браузеры сначала загружают, затем анализируют и исполняют каждый скрипт перед тем, как переходить к следующему файлу в очереди на загрузку. В результате каждый вызов скрипта на вашей странице блокирует процесс загрузки и оказывает негативное влияние на скорость загрузки.

Ниже приведена временная диаграмма, которая демонстрирует процесс загрузки медленных JavaScript-файлов. Загрузка скриптов блокирует параллельную загрузку фоновых картинок, которые идут сразу за ним:

Рис. 7.1. Временнáя диаграмма: блокирующее поведение JavaScript-файлов

Число загрузок с одного хоста

Над временной диаграммой (кроме блокирования картинок) нам также стоит задуматься о том, что картинки после скрипта загружаются только по две. Это происходит из-за ограничений на число файлов, которые могут быть загружены параллельно. В IE <= 7 и Firefox 2 можно параллельно загружать только 2 файла (согласно HTTP 1.1 спецификации), но и в IE8, и в FF3 это число увеличено уже до 6.

Можно обойти это, используя несколько доменов для загрузки ваших файлов, потому что ограничение работает только на загрузку двух компонентов с одного хоста (более подробно эта проблема была рассмотрена в пятой главе). Однако следует понимать, что JavaScript блокирует загрузки со всех хостов. В действительности в приведенном выше примере скрипт располагается на другом домене, нежели картинки, однако по-прежнему блокирует их загрузку.

Если в силу каких-либо причин не удается воспользоваться преимуществами «отложенной» загрузки, то следует размещать вызовы на внешние файлы скриптов в низу страницы, прямо перед закрывающим тегом </body>. В действительности это не ускорит загрузку страницы (скрипт по-прежнему придется загрузить в общем потоке), однако поможет сделать отрисовку страницы более быстрой. Пользователи почувствуют, что страница стала быстрее, если увидят какую-то визуальную отдачу в процессе загрузки.

Неблокирующие скрипты

На самом деле, существует довольно простое решение для устранения блокировки загрузки: нам нужно добавлять скрипты динамически, используя DOM-методы. Это как? Попробуем создать новый элемент <script> и прикрепить его к <head>:

var js = document.createElement('script');

js.src = 'myscript.js';

var head = document.getElementsByTagName('head')[0];

head.appendChild(js);

Ниже приведена диаграмма загрузки для нашего тестового случая, но для загрузки скриптов уже используется описанная технология. Заметим, что скрипты загружаются так же долго, но это не влияет на одновременную загрузку других компонентов (рис. 7.2).