Pro jQuery
Адам Фриман
Обработка событий 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 метод.