Сайт Игоря Кононученко   Статьи

SmartInterval — класс для эффективной обработки повторяющихся событий

14 апреля 2010

Проблема — частый вызов ресурсоемких кусков кода

Рассмотрим пару примеров.

В поисковом поле пользователь набирает текст. При кадом нажатии инициируется отправка аякс-запросов к серверу. Сервер выполняет поиск в базе данных и возвращает ответ.

Пользователь, что-то набирает в текстовом поле, а интерфейс не содержит кнопки сохранения. Преполагается, что все что набирает пользователь и так сохраняется. Опять же, на каждое нажатие кнопки отправляется затратный запрос. Пробуем:

Еще пример. На странице обрабатывается событие onmosemove. При каждом вызове обработчика страница производит какие-либо ресурсозатратные пересчеты. Смотрим:

Поводите мышью

Решение

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

У меня получился такой код:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
var SmartInterval = jQuery.Class.create({
	 
	 init: function(interval, callback){
		this.interval = interval;
		this.callback = callback;
		
		this.execute =  function()
		 {
		 	this.args = arguments;
		 	this.doAction();
		 }.bind(this);
	 },
	 msBetween: function(startDate, endDate)
	 {
		seconds = (endDate.getTime() - startDate.getTime());   
		return Math.round(seconds); 
	 },
	 doAction: function()
	 {
		if(!this.executionStart) this.executionStart = new Date();
	
	 	var timeSince = this.msBetween(this.executionStart, new Date());
		var func = function(){
			if (timeSince > this.interval) {
				this.callback.apply(this, this.args);
				this.executionStart = null
				this.timeoutSet = false;
			}
			else 
				if (!this.timeoutSet) {
					this.timeoutSet = true;
					setTimeout(this.doAction.bind(this), this.interval);
				}
		}.bind(this);
		
		setTimeout(func, 10);
		
	 }
	
});

Использовать так:

1
2
//вызвать callback спустя 1 секунду от конца взаимодействия
$("#el").mousemove((new SmartInterval(1000, callback)).execute);

Теперь проверим.

Клавиатура:

Мышь:

Поводите мышью

В конце

Замечу, что я использовал classy.js и свою bind-функцию.

Скачать smartInterval.js.

Вопросы и замечания буду рад увидеть на почте:).

Про создание этого сайта
Движок презентации в браузере
Ctrl
Перетаскивание файлов в браузер (Drag and Drop, XMLHttpRequest)
Анимированный баннер средствами CSS3