Главная страница   /   15.5. Обработка событий Ajax (Pro jQuery

Pro jQuery

Pro jQuery

Адам Фриман

15.5. Обработка событий Ajax

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

Таблица 15-3: Настройки для событий Ajax
Настройка Описание
beforeSend Указывает функцию, которая будет вызвана, прежде чем начнется Ajax запрос
complete Указывает функцию, которая будет вызвана, когда Ajax запрос пройдет успешно или не выполнится
error Указывает функцию, которая будет вызвана, если Ajax запрос не выполнится
success Указывает функцию, которая будет вызвана, если Ajax запрос пройдет успешно

Совет

Настройки, описанные в таблице 15-3, касаются локальных событий, что обозначает, что они работают с отдельными Ajax запросами. Также вы можете использовать ряд глобальных событий, о которых я расскажу далее в этой главе в разделе "Использование глобальных Ajax событий".

Работа с запросами, выполненными успешно

Когда я показывал использование настройки success, я упустил в функции пару аргументов. Этими аргументами являются сообщение статуса, описывающее результат выполнения запроса, и jqXHR объект. В листинге 15-5 показано использование функции, которая принимает эти параметры.

Листинг 15-5: Получение всех аргументов функцией, которая работает с запросами, выполненными успешно
<script type="text/javascript">
	$(document).ready(function () {
		$.ajax("mydata.json", {
			success: function (data, status, jqxhr) {
				console.log("Status: " + status);
				console.log("jqXHR Status: " + jqxhr.status + " " + jqxhr.statusText);
				console.log(jqxhr.getAllResponseHeaders());

				var template = $('#flowerTmpl');
				template.tmpl(data.slice(0, 3)).appendTo("#row1");
				template.tmpl(data.slice(3)).appendTo("#row2");
			}
		});
	});
</script>

Аргумент status – строка, которая описывает результат запроса. Функция, которую мы указали, используя настройку success, работает только с успешно выполненными запросами, так что, в основном, этот аргумент имеет значение success. Исключением можно назвать тот случай, если вы используете настройку ifModified, о которой я расскажу далее в этой главе в разделе "Игнорирование неизмененных данных".

Функции обратного вызова для Ajax событий следуют тому же шаблону, и их аргумент более полезен для некоторых других событий.

Последним аргументом является jqXHR объект. Вам не нужно предварительно узнавать статус запроса, прежде чем работать с jqXHR объектом, поскольку вы знаете, что функция выполняется, только если запрос прошел успешно. В этом примере я использовал jqXHR объект, чтобы получить информацию о статусе запроса и заголовки, которые сервер включил в ответ, и вывел результат на консоль. Результат этого примера следующий (хотя вы можете увидеть другой набор заголовков, в зависимости от используемого вами веб сервера):

Status: success
jqXHR Status: 200 OK
Date: Sat, 22 Oct 2011 09:19:03 GMT
X-Powered-By: ASP.NET
Content-Length: 437
Last-Modified: Wed, 19 Oct 2011 12:49:28 GMT
Server: Microsoft-IIS/7.5
ETag: "c2d4ec895d8ecc1:0"
Content-Type: application/json
Cache-Control: no-cache
Accept-Ranges: bytes

Работа с ошибками запросов

Мы используем настройку error, чтобы указать функцию, которая будет вызвана, если запрос "провалился". В листинге 15-6 показан пример.

Листинг 15-6: Использование настройки error
<style type="text/css">
	.error {
		color: red;
		border: medium solid red;
		padding: 4px;
		margin: auto;
		width: 200px;
		text-align: center;
	}
</style>
<script type="text/javascript">
	$(document).ready(function () {
		$.ajax("NoSuchFile.json", {
			success: function (data, status, jqxhr) {
				var template = $('#flowerTmpl');
				template.tmpl(data.slice(0, 3)).appendTo("#row1");
				template.tmpl(data.slice(3)).appendTo("#row2");
			},
			error: function (jqxhr, status, errorMsg) {
				$('<div class=error/>')
					.text("Status: " + status + " Error: " + errorMsg)
					.insertAfter('h1');
			}
		});
	});
</script>

В этом примере я запросил файл с именем NoSuchFile.json, которого не существует на веб сервере. Это гарантирует, что запрос не выполнится и будет вызвана функция, которую я указал настройкой error. Аргументами функции являются jqXHR объект, сообщение о статусе и сообщение об ошибке ответа сервера. В функцию я добавил элемент div, чтобы показать значение аргументов status и errorMsg, как показано на рисунке 15-1.

Рисунок 15-1: Отображение сообщения об ошибке

Аргумент status может быть одним из представленных в таблице 15-4 значений.

Таблица 15-4: Значения статуса ошибки
Настройка Описание
abort Показывает, что запрос был прерван (используя jqXHR объект)
error Обозначает общую ошибку, обычно сообщаемую сервером
parsererror Показывает, что данные, возвращенные сервером, не могут быть разобраны
timeout Показывает, что время запроса истекло, до того как ответил сервер

Аргумент errorMsg меняется в зависимости от статуса (аргумента status). Если значение status равно error, тогда для errorMsg значением будет текстовая часть ответа сервера. Вот для этого примера ответ сервера был 404 Not Found, поэтому errorMsg будет Not Found.

Если статусом является timeout, значением errorMsg также будет timeout. Можно указать период времени, после которого истечет время запроса, используя настройку timeout, о чем я расскажу далее в этой главе в разделе "Установка тайм-аутов и заголовков".

Если status равен parsererror, тогда errorMsg будет содержать информацию о проблеме. Эта ошибка возникает, если данные неправильно сформированы или если сервер возвращает неправильный тип MIME для данных. Можно переписать тип данных, используя настройку dataType. И наконец, если запрос будет прерван (использована настройка abort), тогда значения статуса и errorMsg будут равны abort.

Совет

Хотя я отобразил в документе значения status и errorMsg, в принципе, они не несут никакой смысловой нагрузки для пользователя, поскольку сообщения требуют некоторого понимания того, что происходит внутри веб приложения, и они не содержат никаких указаний того, как можно решить проблему.

Работа с завершенными запросами

Можно использовать настройку complete, чтобы указать функцию, которая будет вызвана, когда завершится Ajax запрос, независимо от того, будет он удачным или нет. В листинге 15-7 показан пример.

Листинг 15-7: Использование настройки complete
<script type="text/javascript">
	$(document).ready(function () {
		$.ajax("mydata.json", {
			success: function (data, status, jqxhr) {
				var template = $('#flowerTmpl');
				template.tmpl(data.slice(0, 3)).appendTo("#row1");
				template.tmpl(data.slice(3)).appendTo("#row2");
			},
			error: function (jqxhr, status, errorMsg) {
				$('<div class=error/>')
					.text("Status: " + status + " Error: " + errorMsg)
					.insertAfter('h1');
			},
			complete: function (jXHR, status) {
				console.log("Completed: " + status);
			}
		});
	});
</script>

Функция, указанная настройкой complete, вызывается после функций, указанных настройками success и error. В той функции вы получаете гораздо меньше информации от jQuery, хотя вы получите широкий спектр значений аргумента status, как показано в таблице 15-5.

Таблица 15-5: Событийные настройки Ajax
Настройка Описание
abort Показывает, что запрос был прерван (используя jqXHR объект)
error Обозначает общую ошибку, обычно сообщаемую сервером
notmodified Показывает, что запрашиваемый контент не был модифицирован с тех пор, как он запрашивался в последний раз (более подробную информацию вы можете получить в разделе "Игнорирование немодифицированных данных")
parsererror Показывает, что данные, возвращенные сервером, не могут быть разобраны
success Показывает, что запрос был успешно выполнен
timeout Показывает, что время запроса истекло, до того как ответил сервер

Можно было бы попытаться использовать настройку complete, чтобы указать одну единственную функцию, которая может обрабатывать все результаты запроса, но если вы это сделаете, это будет обозначать, что вы не получите никакой выгоды от того, как jQuery обрабатывает данные и ошибки. Самым лучшим подходом является использование настроек success и error и тщательная организация аргументов общей функции, как показано в листинге 15-8.

Листинг 15-8: Использование одной функции для обработки всех результатов запроса
<script type="text/javascript">
	$(document).ready(function () {
		$.ajax("mydata.json", {
			success: function (data, status, jqxhr) {
				handleResponse(status, data, null, jqxhr);
			},
			error: function (jqxhr, status, errorMsg) {
				handleResponse(status, null, errorMsg, jqxhr);
			}
		});
		function handleResponse(status, data, errorMsg, jqxhr) {
			if (status == "success") {
				var template = $('#flowerTmpl');
				template.tmpl(data.slice(0, 3)).appendTo("#row1");
				template.tmpl(data.slice(3)).appendTo("#row2");
			} else {
				$('<div class=error/>')
					.text("Status: " + status + " Error: " + errorMsg)
					.insertAfter('h1');
			}
		}
	});
</script>

Конфигурация запросов до их отправки

Настройка beforeSend позволяет указать функцию, которая будет вызвана, прежде чем начнется запрос. Это дает вам возможность сделать конфигурацию в последний момент, дополняя или переопределяя настройки, которые вы передали методу ajax (это может быть полезно, если вы используете один и тот же объект настроек для нескольких запросов). В листинге 15-9 показано использование этой настройки.

Листинг 15-9: Использование настройки beforeSend
<script type="text/javascript">
	$(document).ready(function () {
		$.ajax({
			success: function (data, status, jqxhr) {
				handleResponse(status, data, null, jqxhr);
			},
			error: function (jqxhr, status, errorMsg) {
				handleResponse(status, null, errorMsg, jqxhr);
			},
			beforeSend: function (jqxhr, settings) {
				settings.url = "mydata.json";
			}
		});
		function handleResponse(status, data, errorMsg, jqxhr) {
			if (status == "success") {
				var template = $('#flowerTmpl');
				template.tmpl(data.slice(0, 3)).appendTo("#row1");
				template.tmpl(data.slice(3)).appendTo("#row2");
			} else {
				$('<div class=error/>')
					.text("Status: " + status + " Error: " + errorMsg)
					.insertAfter('h1');
			}
		}
	});
</script>

Аргументами функции являются jqXHR объект (который может быть полезен для указания заголовка запроса или для прерывания запроса, прежде чем он начался) и объект настроек, который вы передали методу ajax. В этом примере я использовал настройку url, чтобы указать URL для Ajax запроса.

Указание нескольких функций обработки событий

Я показал использование только одной функции, которая отвечает на события Ajax запроса, но можно установить для настроек success, error, complete и beforeStart массив функций, каждая из которых будет выполняться, когда будет запущено соответствующее событие. В листинге 15-10 представлен простой пример.

Листинг 15-10: Указание нескольких функций обработки событий
<script type="text/javascript">
	$(document).ready(function () {
		$.ajax("mydata.json", {
			success: [processData, reportStatus]
		});
		function processData(data, status, jqxhr) {
			var template = $('#flowerTmpl');
			template.tmpl(data.slice(0, 3)).appendTo("#row1");
			template.tmpl(data.slice(3)).appendTo("#row2");
		}
		function reportStatus(data, status, jqxhr) {
			console.log("Status: " + status + " Result code: " + jqxhr.status);
		}
	});
</script>

В этом примере я добавил настройке success массив из двух функций, одна из которых использует данные, чтобы добавить элементы в документ, а вторая выводит информацию на консоль.

Совет

Вы также можете использовать jqXHR объект, чтобы зарегистрировать слушателей событий, как часть общего jQuery для отложенных объектов, о чем я расскажу в главе 35.

Настройка содержания для события

Настройка context позволяет указать элемент, на который будет указывать this, когда включена функция события. Это может быть полезным для элементов, которые являются легкими целями в документе, и тогда не нужно выбирать их в функции обработки событий. В листинге 15-11 показан пример.

Листинг 15-11: Использование настройки context
<script type="text/javascript">
	$(document).ready(function () {
		$.ajax("mydata.json", {
			context: $('h1'),
			success: function (data, status, jqxhr) {
				var template = $('#flowerTmpl');
				template.tmpl(data.slice(0, 3)).appendTo("#row1");
				template.tmpl(data.slice(3)).appendTo("#row2");
			},
			complete: function (jqxhr, status) {
				var color = status == "success" ? "green" : "red";
				this.css("border", "thick solid " + color);
			}
		});
	});
</script>

В этом примере я устанавливаю настройку context для объекта jQuery, содержащего элементы h1 документа. В функции, указанной настройкой complete, я использую метод css для объекта jQuery (на который я ссылаюсь this), чтобы установить рамку для выбранных элементов (или элемента, потому что в документе есть только один такой), меняя цвета в зависимости от статуса запроса.

Совет

Используя настройку context, можно работать с любым объектом, но вы должны четко знать, как правильно работать с таким объектом. Например, если вы решили, что содержанием должен быть HTMLElement, тогда убедитесь, что передали объект $ функции, прежде чем вызвать для него любой jQuery метод.