JavaScript без задержек

Владимир | | Ajax, JavaScript, Web разработка.

javascript load delays

Название получилось довольно громкое 🙂 На самом деле эта статья не об устранении задержек, а скорее об изменении порядка загрузки и выполнения JS скриптов. Но с точки зрения посетителя некоторые задержки действительно исчезнут, точнее они будут там где он ожидает их увидеть 😉

Я как-то путано рассказываю 🙂 , на самом деле все довольно просто.

Недавно на почтовом сервере ukr.net (в web интерфейсе) я заметил довольно неприятный баг. Загружается web интерфейс, я кликаю по письму и вместо сообщения «Загрузка данных…» вижу «Для просмотра письма включите поддержку JavaScript в браузере и перезагрузите страницу».

Естественно, я точно знаю, что JavaScript у меня включен и перезагружать ничего не стал. Через две-три секунды сообщение исчезло и на его месте появилось письмо.

Работу скриптов ukr.net я анализировать не стал, но в общем-то о причине можно догадаться. Скорее всего, возникла задержка при загрузке JS файла со скриптом, который должен изменять «Включите JS…» на «Загрузка данных..».

Раньше я этот момент не замечал, но у меня нет ограничений по скорости на UA-IX трафик, да и сам ukr.net стабильно работает.

Тем не менее, проблема со скоростью загрузки существует и касается всех, а не только крупных порталов.

Рассмотрим реальную ситуацию.

Нужно создать страничку на которой часть данных подгружается ajax запросом. При этом, хотелось бы использовать какую-нибудь библиотеку вроде jQuery. И, конечно, нужно чтобы посетители с отключенным JavaScript видели соответствующие сообщения.

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

Сообщение «Включите JavaScript…» должно быть вставлено в тело страницы, потому что иначе посетитель с отключенным JS его не увидит.

Поэтому, если код, который убирает это сообщение будет ждать окончания загрузки библиотеки, то какое-то время сообщение будет висеть и путать посетителей с включенным JS.

С другой стороны, нам ведь не обязательно использовать библиотеку для того, чтобы изменить текст в одном из блоков на странице 😉

Т.е. мы можем разбить JS код на две части.

Первая – убирает сообщения «Включите JavaScript…» (эта часть не должна использовать никаких библиотек и должна выполняться прежде всего).

Вторая – выполняет всю остальную работу. Подключать эти скрипты нужно после скриптов библиотек.

Взгляните на следующий пример.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">

<head>
    <title>JavaScript Load Delays</title>
    
    <meta http-equiv="content-type" content="text/html;charset=utf-8" />
    <meta http-equiv="Content-Style-Type" content="text/css" />
    
</head>

<body>

    <div id="dataFromServer">Пожалуйста, включите поддержку JavaScript в браузере и перезагрузите страницу.</div>
    
    <script type="text/javascript">
    //этот код выполняется без использования jQuery
    //убираем сообщение о том, что нужно включить JS
    document.getElementById('dataFromServer').innerHTML = '';
    </script>
    <script type="text/javascript" src="jquery-1.3.2.min.js"></script>
    <script type="text/javascript">
    $(function() {
        //этот код выполняется после загрузки jQuery
        var dataBlock = $('#dataFromServer');
        dataBlock.html('<img src="ajax-loader.gif" /> Подождите, идет загрузка данных');
        $.get('getdata.php', '', function(response) {
            dataBlock.html(response);
        });
    });
    </script>
</body>

</html>

Как видите, страница содержит один блок div с сообщением «Пожалуйста, включите поддержку JavaScript…». Если у посетителя JS отключен, то он его и увидит.

В конце страницы идут три тега script.

В первом находится код, который просто изменяет сообщение в единственном блоке на нашей странице. Обратите внимание, тут используется метод getElementById('dataFromServer'), а не $('#dataFromServer').

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

Второй тег script – библиотека jQuery.

Третий – код, который отправляет ajax запрос к серверу. Тут уже используется jQuery.

Как видите, чуда не произошло. Быстрее ничего грузиться не стало. Просто теперь задержка появляется после того, как будет выведено сообщение «Подождите, идет загрузка …».

Посмотреть как это работает, можно на демонстрационной страничке.

Demo

Примечание. PHP скрипт (getdata.php) выглядит так.

<?php
//задержка на 3 секунды
sleep(3);

echo 'Эта строка получена от сервера';

//end of getdata.php

Тут просто создана задержка для того, чтобы был заметен момент загрузки данных при скоростном соединении.

Как всегда, я буду рад услышать ваши вопросы и замечания 😉

Постовой

Вопрос: сколько стоят услуги бухгалтера? Ответ: от 3000 р. в месяц.

  • noscrip нет? 🙂

    • efdsa

      Это совершенно другое…
      Думаю, что автору надо пополнить эту статью инфой про
      on-demand javascript.

  • noscrip нет? 🙂

    • efdsa

      Это совершенно другое…
      Думаю, что автору надо пополнить эту статью инфой про
      on-demand javascript.

  • Действительно непонятно, чем автору так не угодил стандартный для HTML и поддерживаемый абсолютно всеми браузерами тег ? А на ukr.net похоже не очень добросовестные web-мастера… либо просто временный дизайн или даже просто неполадка =)

  • Действительно непонятно, чем автору так не угодил стандартный для HTML и поддерживаемый абсолютно всеми браузерами тег ? А на ukr.net похоже не очень добросовестные web-мастера… либо просто временный дизайн или даже просто неполадка =)

  • Чистяков Денис

    Действительно не понятно, зачем такие сложности, есть ноускрипт, который как раз для этого.
    Лично я бы в див-контейнер поместил rfhnbyre-прелоад сразу в html'е, после загрузки заменял бы все в контейнере на ответ сервера, а в noscrip вставлял сообщение и style для скрытия прелоада и контейнера.

    • Чистяков Денис

      ой, там конечно картинку-прелоад

      • style внутри noscript — пройдет через валидатор? для xhtml по-моему, нет, хотя браузерам вроде без разницы.

  • Чистяков Денис

    Действительно не понятно, зачем такие сложности, есть ноускрипт, который как раз для этого.
    Лично я бы в див-контейнер поместил rfhnbyre-прелоад сразу в html'е, после загрузки заменял бы все в контейнере на ответ сервера, а в noscrip вставлял сообщение и style для скрытия прелоада и контейнера.

    • Чистяков Денис

      ой, там конечно картинку-прелоад

      • style внутри noscript — пройдет через валидатор? для xhtml по-моему, нет, хотя браузерам вроде без разницы.

  • Ну ок, допустим, мы не знаем о теге noscript или у нас есть какие-то причины его неиспользовать.
    Тогда логичней было бы сразу вывести сообщение «загрузка» в строке document.getElementById('dataFromServer').innerHTML =, а не очищать ее, ждать загрузку jQuery и только потом это делать.

    Кстати, можете рассказать, почему код внутри $(function() { выполняется только после загрузки jQuery?
    Спасибо 🙂

    • efdsa

      Если нету jQuery он не выполнится 🙂
      А так это короткая форма onLoad события

      • Ну ок, то что без jQuery он не выполнится — это понятно. Я хотел понять, почему в таком случае исключена возможность, что мы получим ошибку в следствии попытки вызвать функцию $(), которая еще не объявлена.

        • $(function() {
          это сокращенная форма
          $(document).ready(function() {

          без jquery, конечно, не работает.

          Идея была в том, что сообщение «Загрузка…» выводится до того, как загрузится jQuery, т.е. пока «висит» это сообщение будет загружаться jQuery и отправляться ajax запрос.

  • Ну ок, допустим, мы не знаем о теге noscript или у нас есть какие-то причины его неиспользовать.
    Тогда логичней было бы сразу вывести сообщение «загрузка» в строке document.getElementById('dataFromServer').innerHTML =, а не очищать ее, ждать загрузку jQuery и только потом это делать.

    Кстати, можете рассказать, почему код внутри $(function() { выполняется только после загрузки jQuery?
    Спасибо 🙂

    • efdsa

      Если нету jQuery он не выполнится 🙂
      А так это короткая форма onLoad события

      • Ну ок, то что без jQuery он не выполнится — это понятно. Я хотел понять, почему в таком случае исключена возможность, что мы получим ошибку в следствии попытки вызвать функцию $(), которая еще не объявлена.

        • $(function() {
          это сокращенная форма
          $(document).ready(function() {

          без jquery, конечно, не работает.

          Идея была в том, что сообщение «Загрузка…» выводится до того, как загрузится jQuery, т.е. пока «висит» это сообщение будет загружаться jQuery и отправляться ajax запрос.

  • есть еще один вариант
    document.documentElement.id = "js"

    .noJs { display:block; }
    #js .noJs { display:none; }

    Включите JavaScript

    • парсер 🙁
      document.documentElement.id = "js"

      .noJs { display:block; }
      #js .noJs { display:none; }

      Включите JavaScript

  • есть еще один вариант
    document.documentElement.id = "js"

    .noJs { display:block; }
    #js .noJs { display:none; }

    Включите JavaScript

    • парсер 🙁
      document.documentElement.id = "js"

      .noJs { display:block; }
      #js .noJs { display:none; }

      Включите JavaScript

  • Привет. Давно почитываю твой блог, очень интересные примеры кода.

    Извиняюсь, что может быть не совсем в тему.

    Сейчас создаю программу, в ней объединены несколько парсереров различных ресурсов. Скрипты парсинга запускаются по курлу и ведут лог своих действий в БД, который можно посмотреть на отдельной странице. Проблема в следующем:

    Скрипты начинаются так:

    @ini_set('max_execution_time',0);
    @set_time_limit(0);

    1. Я слышал что не все хостинги и даже VDS поддерживают такие команды, и мне хотелось бы выполнять парсинг, используя возможное время выполнения скрипта на хостинге.

    2. Скрипты порой зависают при парсинге, хотелось бы иметь возможность продолжать парсинг с последнего момента.

    3. Логирование. Хочу выводить лог из базы в окошке, чтобы обновлялся он через AJAX, не смог найти подобных решений в интернете. Но скорее всего подойдут примеры простых чатов на jquery.

    • На VDS вы можете установить свой сервер, т.е. настроить php.ini так как вам хочется. На shared хостинге вам, конечно, управлять временем выполнением скрипта не дадут.
      Поэтому в скрипте после каждого запроса curl'ом нужно считать время, которое выполняется скрипт, например, с помощью функции time() и принимать решение, прекратить выполнение или продолжить.
      Чтобы продолжить парсинг с последнего момента, результаты предыдущих операций нужно где-то сохранять, например, в БД. Хотя если скрипт «завис» нужно искать причину, а не надеяться, что он правильно все сохранит и удастся нормально продолжить его выполнение.
      Для вывода текущего состояния достаточно периодически отправлять ajax запросы php скрипту, который выводит лог, по таймеру (смотрите функции setTimeout() и setInterval())

  • Привет. Давно почитываю твой блог, очень интересные примеры кода.

    Извиняюсь, что может быть не совсем в тему.

    Сейчас создаю программу, в ней объединены несколько парсереров различных ресурсов. Скрипты парсинга запускаются по курлу и ведут лог своих действий в БД, который можно посмотреть на отдельной странице. Проблема в следующем:

    Скрипты начинаются так:

    @ini_set('max_execution_time',0);
    @set_time_limit(0);

    1. Я слышал что не все хостинги и даже VDS поддерживают такие команды, и мне хотелось бы выполнять парсинг, используя возможное время выполнения скрипта на хостинге.

    2. Скрипты порой зависают при парсинге, хотелось бы иметь возможность продолжать парсинг с последнего момента.

    3. Логирование. Хочу выводить лог из базы в окошке, чтобы обновлялся он через AJAX, не смог найти подобных решений в интернете. Но скорее всего подойдут примеры простых чатов на jquery.

    • На VDS вы можете установить свой сервер, т.е. настроить php.ini так как вам хочется. На shared хостинге вам, конечно, управлять временем выполнением скрипта не дадут.
      Поэтому в скрипте после каждого запроса curl'ом нужно считать время, которое выполняется скрипт, например, с помощью функции time() и принимать решение, прекратить выполнение или продолжить.
      Чтобы продолжить парсинг с последнего момента, результаты предыдущих операций нужно где-то сохранять, например, в БД. Хотя если скрипт «завис» нужно искать причину, а не надеяться, что он правильно все сохранит и удастся нормально продолжить его выполнение.
      Для вывода текущего состояния достаточно периодически отправлять ajax запросы php скрипту, который выводит лог, по таймеру (смотрите функции setTimeout() и setInterval())

  • Очень интересная тема, но фрейворками, слава богу, почти не пользуюсь. Почему не ноускрипт тоже интересно.

  • Очень интересная тема, но фрейворками, слава богу, почти не пользуюсь. Почему не ноускрипт тоже интересно.

  • По-поводу noscript.
    Сразу хочу извиниться 🙂 Конечно, его нужно было использовать.

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

    О том, что нужно проверять включен js или нет я, как обычно, вспомнил в самый последний момент, когда менять разметку страницы совсем не хотелось 🙂 Я, конечно, понимаю, что так делать не правильно, но природная лень … 😉

    Поэтому использовал такое решение, а когда писал пост — начисто об этом забыл.
    В общем, еще раз мои извинения.

  • По-поводу noscript.
    Сразу хочу извиниться 🙂 Конечно, его нужно было использовать.

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

    О том, что нужно проверять включен js или нет я, как обычно, вспомнил в самый последний момент, когда менять разметку страницы совсем не хотелось 🙂 Я, конечно, понимаю, что так делать не правильно, но природная лень … 😉

    Поэтому использовал такое решение, а когда писал пост — начисто об этом забыл.
    В общем, еще раз мои извинения.

  • Интригующий заголовок 🙂 и обычный текст. Как детектив прям.
    Google как раз проводит семинар или тпа того насчет как раз проблемы ускорения JS. Так что быть может скоро будет все работать быстрее

  • Интригующий заголовок 🙂 и обычный текст. Как детектив прям.
    Google как раз проводит семинар или тпа того насчет как раз проблемы ускорения JS. Так что быть может скоро будет все работать быстрее

  • Пожалуйста, включите поддержку JavaScript в браузере и перезагрузите страницу.

    document.getElementById('dataFromServer').innerHTML = "Идёт загрузка...";

    // Грузим!)

    Чуть исправил и думаю, понятен смысл? 🙂
    JS не работает — всё ок, выдаётся сообщение о надобности включения.
    JS работает — всё ок и сразу выдаётся сообщение о загрузке 🙂

    Кстати, тоже открыл блог о JS http://vl.vg/, добро пожаловать 🙂

    • Да, вы правы. Просто в общем случае, загрузка не обязательно начнется сразу после открытия страницы.

      Мне понравились эффекты (подсветка) на вашем блоге. Думаю, у вас получился бы интересный пост о них.

      • Спасибо! А можно поподробней, какая именно подсветка?)

        • В сайдбаре, выделение пунктов меню при наведении, подсветка счетчиков и выделение блоков в шапке.

        • Хочу вас заверить, что всё это сделано на чистом css(с некоторыми элементами css3) и •
          Счётчики — игра с css3 свойством opacity
          Вот и всё, никакого JS 🙂

        • Тогда прошу прощения 🙂 Просто я увидел, что вы грузите jQuery и… не подумал, что используется CSS3. Всё-таки поддержка этой спецификации на сегодняшний день оставляет желать лучшего.

        • Ну да, поддержка не очень, но пока ни один читатель не возмутился 🙂
          У меня в блоге довольно много всяких штук основано на CSS3 и просто псевдоселекторах :hover и :focus
          Хотя jQuery использую достаточно активно 🙂

        • А с чего бы им возмущаться? Они ведь эффектов не видят и не знают, что что-то не работает 🙂
          К тому же, учитывая тематику блога, не думаю, что многие читатели пользуются IE6 🙂

        • Видимо у блогеров нет этого атавизма насчёт IE6 🙂
          Они им вообще не пользуются 😀
          Firefox 3 36.1%
          Opera 9 21.7%
          Opera 10 14.6%
          Explorer 7 13.9%
          Firefox 2 7.8%
          Chrome 5.0%
          Safari 4 0.7%
          Mozilla 1 0.2%

        • У меня расклад по процентам примерно тоже самый 🙂 , но проблема в том, что ваш сайт даже в IE8 выглядит хуже чем в FF. Я не могу сказать — плохо, но отличия видны сразу.

        • Всё делом в том, что я подключал Jquery 1.4pre, который вызывал во всех IE ошибку. Подключил jQuery 1.3.2 с гугла, всё отличн.
          У меня дизайн основан на полной CSS3. CSS3 файл подключал посредством JS. IE8- ничего из CSS3 не поддерживают, вот такой и вид плохой 🙂

  • Пожалуйста, включите поддержку JavaScript в браузере и перезагрузите страницу.

    document.getElementById('dataFromServer').innerHTML = "Идёт загрузка...";

    // Грузим!)

    Чуть исправил и думаю, понятен смысл? 🙂
    JS не работает — всё ок, выдаётся сообщение о надобности включения.
    JS работает — всё ок и сразу выдаётся сообщение о загрузке 🙂

    Кстати, тоже открыл блог о JS http://vl.vg/, добро пожаловать 🙂

    • Да, вы правы. Просто в общем случае, загрузка не обязательно начнется сразу после открытия страницы.

      Мне понравились эффекты (подсветка) на вашем блоге. Думаю, у вас получился бы интересный пост о них.

      • Спасибо! А можно поподробней, какая именно подсветка?)

        • В сайдбаре, выделение пунктов меню при наведении, подсветка счетчиков и выделение блоков в шапке.

        • Хочу вас заверить, что всё это сделано на чистом css(с некоторыми элементами css3) и •
          Счётчики — игра с css3 свойством opacity
          Вот и всё, никакого JS 🙂

        • Тогда прошу прощения 🙂 Просто я увидел, что вы грузите jQuery и… не подумал, что используется CSS3. Всё-таки поддержка этой спецификации на сегодняшний день оставляет желать лучшего.

        • Ну да, поддержка не очень, но пока ни один читатель не возмутился 🙂
          У меня в блоге довольно много всяких штук основано на CSS3 и просто псевдоселекторах :hover и :focus
          Хотя jQuery использую достаточно активно 🙂

        • А с чего бы им возмущаться? Они ведь эффектов не видят и не знают, что что-то не работает 🙂
          К тому же, учитывая тематику блога, не думаю, что многие читатели пользуются IE6 🙂

        • Видимо у блогеров нет этого атавизма насчёт IE6 🙂
          Они им вообще не пользуются 😀
          Firefox 3 36.1%
          Opera 9 21.7%
          Opera 10 14.6%
          Explorer 7 13.9%
          Firefox 2 7.8%
          Chrome 5.0%
          Safari 4 0.7%
          Mozilla 1 0.2%

        • У меня расклад по процентам примерно тоже самый 🙂 , но проблема в том, что ваш сайт даже в IE8 выглядит хуже чем в FF. Я не могу сказать — плохо, но отличия видны сразу.

        • Всё делом в том, что я подключал Jquery 1.4pre, который вызывал во всех IE ошибку. Подключил jQuery 1.3.2 с гугла, всё отличн.
          У меня дизайн основан на полной CSS3. CSS3 файл подключал посредством JS. IE8- ничего из CSS3 не поддерживают, вот такой и вид плохой 🙂

  • Макс

    Добрый день, Владимир!
    А подскажите, как передавать ответ от сервера, что произошла ошибка? например, на сервере нет подключения к базе? я делал так:
    сервер-
     odbc_errormsg())) ); return json_encode;
    ?>
    такого соединения нет, заведомо с ошибкой дан логин-пароль
    Клиент-
    $.ajax({        url: 'prosm.php'                        ,data: 'action=check_username&username='+20      ,dataType: 'json'                        ,type: 'post'      ,error:  function(data){   alert('Возникла ошибка: ' + data.err); }
           });  
     
    Алерт выдает undefined. Как передать текст ошибки odbc_errormsg()?
     

    • Когда вы отправляете ajax запрос, в параметре error указывается функция, которая должна быть вызвана если при выполнении запроса возникла ошибка. Обратите внимание, имеются в виду именно ошибки ajax запроса, а не ошибки, которые возникали при выполнении серверного скрипта. В вашем случае запрос выполнен успешно, можете посмотреть в firebug статус ответа (там будет 200 ОК).

      Т.е. нужно  заменить
      error:  function(data) …
      на
      success:  function(data) …