Blog. Just Blog

Технология COMET на JavaScript

Версия для печати Добавить в Избранное Отправить на E-Mail | Категория: Web-мастеру и не только | Автор: ManHunter
Технология COMET на JavaScript
Технология COMET на JavaScript

Если вы, прочитав заголовок и посмотрев на картинку, вдруг подумали чего-нибудь странное, то напрасно. К небесным телам и моющим средствам эта статья никакого отношения не имеет. COMET - это еще одна современная технология веб-строительства, заключающаяся в том, что веб-страница не просто разово или циклично запрашивает контент с сервера, а создает с сервером постоянное HTTP-соединение и ждет от него передачи данных. Это позволяет пользователям веб-приложения более оперативно получать все возникающие на сервере события (пример - мгновенное уведомление о новом сообщении в социальных сетях). В идеальном варианте для этого на сервере разворачивается специальное программное обеспечение, сам сервер особым образом конфигурируется, а на клиентской части используются специальные библиотеки для обмена данными. Это если рассматривать использование COMET в контексте больших и серьезных проектов. Но для рядового сайта, размещенного на обычном хостинге с ограничением времени исполнения скрипта, тоже можно сделать облегченный аналог COMET.

Сперва немного теории, чтобы потом было легче реализовать задумку на практике. В качестве реального примера попробуем реализовать при помощи JavaScript и PHP упомянутый выше счетчик персональных сообщений на странице сайта, который будет немедленно обновляться при получении нового письма.

Обычное соединение
Обычное соединение

При обычном соединении счетчик будет обновляться только при генерации страницы. Чтобы узнать о новом письме пользователю придется постоянно обновлять страницу в браузере. Этот способ создает лишнюю нагрузку на сервер, требует передачи огромных объемов данных, а главное, не удовлетворяет условию задачи - информация о получении письма должна передаваться пользователю сразу же по факту его получения. Так что такой вариант нам не подходит.

Периодические AJAX-запросы ("polling")
Периодические AJAX-запросы ("polling")

Более прогрессивный метод - использование периодических запросов к серверу через AJAX. Например, скрипт из браузера каждые 5 секунд отправляет запрос на серверный скрипт и запрашивает количество новых непрочитанных сообщений. Такой способ называется "polling". В этом случае значительно снижается объем передаваемых данных, но проблема дополнительной нагрузки на сервер решается лишь частично. Остается необходимость периодически отправлять заголовки, затем каждый раз ожидать ответа сервера, даже если никаких изменений на сервере фактически не произошло. Можно дополнительно снизить нагрузку на сервер путем снижения частоты отсылаемых запросов, но это опять же пойдет в ущерб актуальности данных и в разрез с условием задачи о мгновенном информировании пользователя о письме. К примеру, если некое событие произошло через 3 секунды после последнего запроса, то при интервале опроса в 10 секунд мы получим уведомление об этом событии только через 7 секунд от времени его фактического возникновения.

Запросы COMET ("long polling")
Запросы COMET ("long polling")

Наконец мы добрались до технологии COMET. Есть несколько вариантов ее реализации, но, к сожалению, практически все они завязаны на конкретном браузере и ведут себя по-своему. Единственным кроссбраузерным и гарантированно работающим решением является так называемая "очередь длинных запросов", или "long polling". Ее суть заключается в следующем. Сначала браузер отправляет AJAX-запрос на сервер и ожидает ответа. Соединение остается открытым до тех пор, пока на сервере не наступит ожидаемое событие (или, как в нашем случае, пока серверный скрипт не отвалится по таймауту). Сразу после наступления события данные отправляются в браузер и соединение закрывается. Браузер после получения данных сразу же открывает новое соединение и все повторяется. Это очень похоже на предыдущий способ "polling", но данные с сервера передаются с максимально возможной актуальностью. Если за время ожидания никаких событий на сервере не случилось, интервал между "долгими" запросами будет гораздо больше, чем при долбежке сервера периодическими опросами. Поэтому еще более минимизируются расходы на передачу заголовков запросов, тем самым еще больше снижается нагрузка на сервер.

С теорией закончили, переходим к практике. Взаимодействие клиентской части и серверной осуществляется в точности как описано в статье про основы AJAX. Разница лишь в том, что на сервер отправляется текущее состояние клиентской части. Это может быть уже известное количество непрочитанных сообщений, ID последней записи в чате, короче, это некое значение или совокупность значений, на основании которых серверная часть будет принимать решение о том, произошло событие или нет. Например, если от браузера пришло, что он уже знает о 5 непрочитанных письмах, а в процессе работы серверного скрипта выяснилось, что их уже 6, то это и считается моментом наступления события, о чем немедленно уведомляется браузер. Или же в примере с чатом, сервер знает, что на этом соединении у пользователя в браузере отрисован чат до сообщения с переданным ID, но за время проверки ID последней записи изменился (добавились сообщения), значит наступило событие, о котором также надо уведомить браузер пользователя и передать новые сообщения. Но может быть и односторонняя связь, то есть серверной части неинтересно текущее состояние клиентской части, он просто передает данные в момент наступления события.

Немного изменилась и функция обработки статуса объекта XMLHttpRequest. В случае любой ошибки следующий запрос перезапускается с небольшой задержкой. Это необходимо, чтобы не нагружать браузер в случае отсутствия сети или не создавать лишнюю нагрузку на сервер, если тот уже перегружен запросами или завис. В случае любого удачного ответа сразу же отправляется следующий запрос.

Лог работы скрипта в FireBug
Лог работы скрипта в FireBug

В качестве серверной части у меня выступает вот такой скрипт. Он просто крутит холостой цикл, который может вылететь за установленный таймаут. В этом случае скрипт завершится с ошибкой и соединение будет перезапущено со стороны браузера.
  1. // Отключить вывод ошибок
  2. error_reporting(0);
  3.  
  4. // Максимальное время выполнения скрипта - 15 секунд
  5. ini_set('max_execution_time'15);
  6.  
  7. // Буферизация вывода
  8. ob_start();
  9.  
  10. // Имитируем упорную работу. При этом время выполнения скрипта
  11. // может быть больше максимально допустимого времени. В этом случае
  12. // скрипт вылетит с ошибкой без какого-либо результата, а соединение
  13. // перезапустится из браузера
  14. $tt=rand(3,20);
  15. for ($i=0$i<$tt$i++) {
  16.     sleep(1);
  17. }
  18.  
  19. // Значение не изменилось по сравнению с предыдущим,
  20. // ничего в браузер не передавать
  21. if ($tt==$_POST['msg_count']) { exit; }
  22.  
  23. // Отправить значение в браузер
  24. echo $tt;
  25. ob_end_flush();
В логе видно несколько итераций, в которых состояние на сервере по сравнению с состоянием клиентской части не изменилось, в этом случае серверный скрипт просто завершает работу по таймауту и не передает никаких данных.

Рабочий пример и полный исходный текст скрипта можно посмотреть на демонстрационной странице.

Поделиться ссылкой ВКонтакте Поделиться ссылкой на Facebook Поделиться ссылкой на LiveJournal Поделиться ссылкой в Мой Круг Добавить в Мой мир Добавить на ЛиРу (Liveinternet) Добавить в закладки Memori Добавить в закладки Google
Просмотров: 5759 | Комментариев: 8

Метки: JavaScript, AJAX
Внимание! Статья опубликована больше года назад, информация могла устареть!

Комментарии

Отзывы посетителей сайта о статье
ManHunter (15.03.2015 в 20:52):
Статью совсем не читал?
Саша (15.03.2015 в 20:35):
а какой сам файл comet.php ?? У меня браузер comet не выдаёт 200 ответ.
ManHunter (06.04.2014 в 15:01):
А что, все браузеры уже стали их поддерживать?
Serega (06.04.2014 в 14:59):
Пришла пора вебсокетов - обновите статью, добавте свеженького материала :)
ManHunter (07.12.2013 в 18:58):
Ну так под это отдельные решения и делаются, на отдельном железе и не на апаче.
Игорь (07.12.2013 в 17:43):
Такая технология у вас убьет апач просто
WWWWWWWWWWWWWWWW...........
ManHunter (04.12.2013 в 09:26):
Интервал обновления данных от 1 до 15 секунд
Михаил (04.12.2013 в 09:24):
на DEMO-странице ничего не отображается(((

Добавить комментарий

Заполните форму для добавления комментария
Имя*:
Текст комментария (не более 2000 символов)*:

*Все поля обязательны для заполнения.
Комментарии, содержащие рекламу, ненормативную лексику, оскорбления и т.п., а также флуд и сообщения не по теме, будут удаляться. Нарушителям может быть заблокирован доступ к сайту.
Наверх
Powered by PCL's Speckled Band Engine 0.2 RC3
© ManHunter / PCL, 2008-2017
При использовании материалов ссылка на сайт обязательна
Время генерации: 0.08 сек. / MySQL: 2 (0.0042 сек.) / Память: 4.5 Mb
Наверх