Как стать автором
Обновить

Обновление информации в фоне

Время на прочтение2 мин
Количество просмотров12K
Всем добрый день.

Недавно я задумался надо вопросом фонового обновления информации и мне пришла в голову одна идея.

Суть задачи — мы находимся на странице списка новостей. Необходимо обновлять список по мере поступления новых новостей. Серверный язык PHP

Рассмотрим классический вариант через постоянные запросы аяксом:
1) Клиент посылает аякс запрос на сервер, например по адресу — /ajax/get_upades&time=xxxxxx
2) PHP смотрит есть ли в базе данных записи, новее чем time
3) Если есть выбирает их и возвращает
4) Если нет ничего не возвращает

В этом случае мы вынуждены постоянно дергать PHP и БД для ответа на вопрос, есть ли новые данные?

Мне очень не понравилась эта идея.

Варианты с long polling мне тоже не понравились в связи с различными трудностями реализации и удержанием большого к-ва открытых соединений

Тогда я решил почему бы не переложить задачу по определению наличия новых данных на сам сервер, полностью минуя PHP

Суть идеи заключается в следующем

Клиент постоянно пингует пустой файл-маркер. Назовем его /ping/new_news

Сервер при отдаче файла посылает заголовок — ETag вида «10aa0f-7-4b877e2d4941c». Это один из заголовков принимающих участие в механизме кеширования. ETag рассчитывается на основании информации inode, size и mtime файла. Т.е. при изменение mtime (времени изменения файла) сервер будет посылать другой ETag.

Все что нам нужно это при вставке новой новости обновить mtime файла например ф-цией touch(), а лучше создать триггер в базе на вставку записи и менять файл

Далее мы пишем небольшой класс. Назовем его Updater

var Updater = function(){
	this.params = {
		period: 		3000,
		url: 			'',
		onModified: 	function(data,x,modified){},
		bgPause:  		false
	};

	this.interval = null;
	this.ETag = '';
	this.lastModified = '';

	this.init = function(params){
		var me = this;
		this.params = $.extend(this.params, params);

		if(this.params.bgPause){
			$(window).blur(function(){ me.pause() });
			$(window).focus(function(){ me.resume() });
		}
	};

	this.start = function(){
		var me = this;
		this.interval = setInterval(function(){ me.doUpdate() }, this.params.period);
	};

	this.doUpdate = function(){
		var me = this;
		$.ajax(this.params.url, {
			success: function(data,status,x){
				if(me.ETag != x.getResponseHeader('ETag')){
					me.params.onModified(data,x,me.lastModified);
					me.lastModified = x.getResponseHeader('Last-Modified');
				}
				me.ETag = x.getResponseHeader('ETag');
			},
			beforeSend: function(x){
				if(me.ETag != '') { x.setRequestHeader('If-None-Match', me.ETag); }
			},
			cache: false
		});
	};

	this.pause = function(){
		clearInterval(this.interval);
		this.interval = null;
	};

	this.resume = function(){
		if(this.interval != null) return;
		this.start();
	};
};


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

Иногда Apache после измения пингуемого файла, продолжает некоторое время отдавать старый Last-Modified и ETag. Добавление параметра cache false у аякс запроса вылечивает эту ситуацию

Для уменьшения к-ва запросов мы перестаем пинговать сервер, когда пользователь не видит нашу страницу
if(this.params.bgPause){
	$(window).blur(function(){ me.pause() });
	$(window).focus(function(){ me.resume() });
}


Вот такая вот идея пришла в голову. Выслушаю Вашу критику, идеи, предложения. Всем спасибо

UPD. Добавлен параметр beforeSend в аякс запрос
Теги:
Хабы:
+33
Комментарии60

Публикации

Изменить настройки темы

Истории

Работа

Ближайшие события