Главная страница   /   15.8. Использование более сложных настроек конфигурации (Pro jQuery

Pro jQuery

Pro jQuery

Адам Фриман

15.8. Использование более сложных настроек конфигурации

В следующих разделах я опишу наиболее интересные и полезные из "продвинутых" настроек, которые вы можете применять к Ajax запросу. Я хочу сказать, что я не часто их использую, но если это нужно, они бесценны. Они предоставляют очень детальное управление над процессом того, как jQuery работает с Ajax.

Оформление синхронного запроса

Настройка async указывает, будет ли запрос выполнен асинхронно. Значение true, которое является значением по умолчанию, обозначает, что будет; значение false обозначает, что запрос будет выполнен синхронно.

Если запрос выполняется синхронно, метод ajax ведет себя как обычная функция, и браузер будет ждать, пока закончится запрос, прежде чем перейдет к выполнению других выражений скрипта. В листинге 15-16 показан пример.

Листинг 15-16: Создание синхронного запроса
<script type="text/javascript">
	$(document).ready(function () {
		var elems;
		$.ajax("flowers.html", {
			async: false,
			success: function (data, status, jqxhr) {
				elems = $(data).filter("div").addClass("dcell");
			}
		});
		elems.slice(0, 3).appendTo('#row1');
		elems.slice(3).appendTo("#row2");
	});
</script>

Это тот же запрос, который я показал вам в главе 14, когда демонстрировал наиболее общие ловушки при использовании Ajax, обновленный для использования низкоуровневого API. Разница в данном случае состоит в том, что настройка async является false. Таким образом, браузер не перейдет к выражениям, которые вызывают методы slice и appendTo, пока запрос не завершится и результаты не будут присвоены переменной elems (предполагая, что запрос пройдет успешно). Создание синхронных запросов с использованием методы ajax – вещь довольно странная, поэтому я рекомендую вам хорошенько обдумывать, нужно ли это вашему веб приложению.

Совет

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

Игнорирование немодифицированных данных

Вы можете использовать настройку ifModified, чтобы получить данные, только если ответ изменился, с тех пор как вы в последний его запрашивали. Это определяется заголовком Last-Modified ответа. Если вам нужно запрашивать те же данные несколько раз в ответ на действия пользователя, вы часто заканчиваете обрабатывать ответ сервера и модифицировать документ, только чтобы представить пользователю то, что уже и так есть. Значением по умолчанию для этой настройки является false, которое говорит jQuery игнорировать заголовок и всегда давать вам данные.

В листинге 15-17 представлен пример использования этой настройки.

Листинг 15-17: Использование настройки ifModified
<script type="text/javascript">
	$(document).ready(function () {
		$('button').click(function (e) {
			$.ajax("mydata.json", {
				ifModified: true,
				success: function (data, status) {
					if (status == "success") {
						$('#row1, #row2').children().remove();
						var template = $('#flowerTmpl');
						template.tmpl(data.slice(0, 3)).appendTo("#row1");
						template.tmpl(data.slice(3)).appendTo("#row2");
					} else if (status == "notmodified") {
						$('img').css("border", "thick solid green");
					}
				}
			});
			e.preventDefault();
		})
	});
</script>

В этом примере значение настройки ifModified равно true. Функция success вызывается всегда, но если содержание не было изменено, с тех пор как я запрашивал его в последний раз, тогда аргумент data будет undefined, а аргумент status будет notmodified. В этом примере я выполняю различные действия, основываясь на аргументе status. Если значение аргумента равно success, тогда я использую аргумент data, чтобы добавить элементы в документ. Если аргумент является notmodified, тогда я использую метод css, чтобы добавить рамку элементам img уже в самом документе.

Я вызываю метод ajax в ответ на событие click элемента button. Это позволяет мне повторять один и тот же запрос, чтобы показать результат использования настройки ifModified, который вы можете увидеть на рисунке 15-3.

Рисунок 15-3: Использование настройки ifModified

Это может быть очень полезная настройка, но я советую использовать ее осторожно. Если вы делаете запрос вследствие действия пользователя (скажем, нажатие кнопки), существует вероятность того, что пользователь нажимает на кнопку, потому что предыдущий запрос не был выполнен таким образом, каким он должен был быть выполнен. Представьте, что вы запрашиваете данные, но метод success содержит ошибку, которая должным образом не обновляет содержание документа; пользователь нажимает на кнопку, чтобы получить правильно отображенный документ. Если неразумно использовать настройку ifModified, вы можете в конечном итоге игнорировать действия пользователя, вынуждая его предпринимать более серьезные меры, чтобы решить проблему.

Работа с кодом статуса ответа

Настройка statusCode позволяет вам реагировать на различные коды статуса, которые возвращаются в HTTP ответах. Вы можете использовать эту возможность в качестве альтернативы настройкам success и error или в качестве их дополнения. В листинге 15-18 показано использование настройки statusCode самой по себе.

Листинг 15-18: Использование настройки statusCode
<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({
			url: "mydata.json",
			statusCode: {
				200: handleSuccessfulRequest,
				404: handleFailedRequest,
				302: handleRedirect
			}
		});
		function handleSuccessfulRequest(data, status, jqxhr) {
			$('#row1, #row2').children().remove();
			var template = $('#flowerTmpl');
			template.tmpl(data.slice(0, 3)).appendTo("#row1");
			template.tmpl(data.slice(3)).appendTo("#row2");
		}
		function handleRedirect() {
			// this function will neber be called
		}
		function handleFailedRequest(jqxhr, status, errorMsg) {
			$('<div class=error>Code: ' + jqxhr.status + ' Message: '
				+ errorMsg + '</div>').insertAfter('h1');
		}
	});
</script>

Вы используете настройку statusCode с объектом-картой, связывающим коды статуса HTTP с функциями, которые должны быть выполнены, когда они возвращаются на сервер. В этом примере я определил три функции и связал их со статусными кодами 200, 404 и 302. Аргумент, переданный функции, зависит от того, отображает ли статусный код успешный запрос или ошибку. Если код представляет успешно выполненный запрос (такой как 200), тогда аргументы будут такими же, как и для функции настройки success. В ином случае (как с кодом 404, который показывает, что требуемый файл не найден) аргументы будут такими же, как и для функции настройки error.

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

Совет

Код 304, который сообщает, что содержание не было изменено с момента последнего запроса, генерируется, только если была использована настройка ifModified. В ином случае jQuery вместо этого отправляет код 200. Смотрите предыдущий раздел для информации о настройке ifModified.

Как вы видите, эта возможность не совсем напрямую раскрывает все статусные коды. Я нахожу эту возможность полезной, когда я нахожусь в процессе отладки взаимодействий между браузером и сервером, обычно чтобы выяснить, почему jQuery не ведет себя так, как мне хотелось бы. Когда я это делаю, я использую настройку statusCode в качестве дополнения к настройкам success и error и вывожу информацию на консоль. Когда я использую эти настройки вместе, сначала выполняются функции настроек success или error, а затем функции, указанные настройкой statusCode.

Очистка данных ответа

Настройка dataFilter позволяет указать функцию, которая будет вызвана для обработки данных, возвращенных сервером. Это очень полезная возможность, если сервер отправляет вам данные, которые являются не совсем тем, что вам надо, либо потому что форматирование не совсем хорошее, либо потому что там содержатся данные, которые вы не хотите обрабатывать. Я нахожу эту настройку полезной при работе с серверами Microsoft ASP.NET, которые могут добавить дополнительные данные в данные JSON. Настройка dataFilter позволяет мне удалять эти данные, прилагая совсем немного усилий. В листинге 15-19 показано использование настройки dataFilter.

Листинг 15-19: Использование настройки dataFilter
<script type="text/javascript">
	$(document).ready(function () {
		$.ajax({
			url: "mydata.json",
			success: function (data, status, jqxhr) {
				$('#row1, #row2').children().remove();
				var template = $('#flowerTmpl');
				template.tmpl(data.slice(0, 3)).appendTo("#row1");
				template.tmpl(data.slice(3)).appendTo("#row2");
			},
			dataType: "json",
			dataFilter: function (data, dataType) {
				if (dataType == "json") {
					var filteredData = $.parseJSON(data);
					filteredData.shift();
					return JSON.stringify(filteredData.reverse());
				} else {
					return data;
				}
			}
		});
	});
</script>

Функции передаются данные, полученные от сервера, и значение настройки dataType. Если настройка dataType не была использована, тогда второй аргумент функции будет undefined. Ваша работа с этой функцией заключается в том, чтобы вернуть отфильтрованные данные. В этом примере я фокусируюсь на типе данных json:

var filteredData = $.parseJSON(data);
filteredData.shift();
return JSON.stringify(filteredData.reverse());

Чтобы упростить этот пример, я сделал кое-что немного излишнее. Во-первых, я конвертировал данные JSON в массив JavaScript, используя jQuery метод parseJSON (это один из утилитарных методов jQuery, который я описываю в главе 33). Затем я использую метод shift, чтобы удалить первый элемент в массиве, и использую метод reverse, чтобы поменять порядок оставшихся элементов в массиве на обратный.

Излишество состоит в том , что вам нужно вернуть из функции строку, поэтому я вызываю метод JSON.stringify, зная, что jQuery конвертирует данные в объект JavaScript перед вызовом функции success. И все же вы видите, что я мог бы удалить элемент из массива, и я мог бы выполнить любое другое действие, которое мне надо. Результат этой функции можно увидеть на рисунке 15-4.

Рисунок 15-4: Удаление элемента и изменение порядка данных при помощи настройки dataFilter

Управление преобразованием данных

Я оставил одну из моих любимых настроек напоследок. Вы, наверное, заметили, что jQuery совершает удобные преобразования, когда получает определенный тип данных. Например, когда jQuery получает данные JSON, он представляет функцию success с JavaScript объектом, а не с сырой JSON строкой.

Вы можете управлять этими преобразованиями, используя настройку converters. Значением этой настройки является объект-карта, который связывает типы данных и функции, используемые для их обработки. В листинге 15-20 показано, как можно использовать эту настройку, чтобы автоматически разбирать (парсить) HTML данные в jQuery объект.

Листинг 15-20: Использование настройки converters
<script type="text/javascript">
	$(document).ready(function () {
		$.ajax({
			url: "flowers.html",
			success: function (data, status, jqxhr) {
				var elems = data.filter('div').addClass("dcell");
				elems.slice(0, 3).appendTo('#row1');
				elems.slice(3).appendTo("#row2");
			},
			converters: {
				"text html": function (data) {
					return $(data);
				}
			}
		});
	});
</script>

В этом примере я зарегистрировал функцию для типа text html. Обратите внимание, что между компонентами MIME типа используется пробел (по сравнению с text/html). Функции передаются данные, полученные от сервера, и она возвращает преобразованные данные. В нашем случае я просто передаю фрагмент HTML, который содержится в файле flowers.html, jQuery $ функции и возвращаю результат. Это обозначает, что я могу вызывать все обычные методы jQuery для объекта, переданного в качестве аргумента данных функции success.

Совет

Типы данных не всегда соответствуют MIME типам, возвращаемым сервером. Например, application/json в методе converters обычно представляется как text json.

Легко увлечься этими преобразованиями. Я всегда стараюсь избегать пользоваться этими функциями сверх необходимого. Например, мне иногда хочется взять данные JSON, применить шаблон данных и передать обратно полученные HTML элементы. И хотя это хороший трюк, он может загнать вас в ловушку, если кто-то другой пытается расширить ваш код или вам нужно в дальнейшем сделать много работы, чтобы получить исходные данные.