Ответ 1
В jQuery 1.5 все API-интерфейсы Ajax имеют объект-оболочку вокруг собственных объектов XHR. Взгляните на:
http://api.jquery.com/jQuery.ajax/#jqXHR
jqxhr.abort(); // should be what you're looking for
Я использую JSONP-вызов ajax для загрузки некоторого контента из другого домена, и все это происходит, если пользователь вызывает "наведение мыши" на кнопку.
Я могу захватить возврат вызова $.ajax() как объект xhr и использовать его для прерывания запроса ajax каждый раз, когда пользователь вызывает "mouseover". Но функция обратного вызова JSONP по-прежнему вызывается, и это вызывает ошибку, и я думаю, что это связано с тем, что метод xhr.abort() не мешает вызывать функцию обратного вызова.
Я попытался окружить вызов $.ajax() с помощью try {} catch (e) {}, но после вызова метода xhr.abort() ошибка продолжается.
Есть ли способ обработать это исключение?
Повышенное исключение выглядит следующим образом (согласно Firebug): jQuery16102234208755205157_1308941669256 не является функцией
И внутренняя структура исключения выглядит так: jQuery16102234208755205157_1308941669256 ({... мои данные json из другого домена....})
В jQuery 1.5 все API-интерфейсы Ajax имеют объект-оболочку вокруг собственных объектов XHR. Взгляните на:
http://api.jquery.com/jQuery.ajax/#jqXHR
jqxhr.abort(); // should be what you're looking for
Основной ответ - это просто тот, который указан здесь: вы действительно не можете abort()
вызвать JSONP. Итак, реальный вопрос: как вы избегаете как избыточных вызовов обратного вызова, так и ошибки, которую вы видите?
Вы не можете использовать try...catch
вокруг обратного вызова, потому что он асинхронный; вам придется поймать его с конца jQuery, а jQuery обычно не обрабатывает исключения, вызванные обратными вызовами. (Я обсуждаю это в своей книге, Async JavaScript.) Вместо этого вы должны использовать уникальный идентификатор для каждого вызова Ajax и, когда вызывается обратный вызов успеха, проверяйте, является ли этот идентификатор таким же, как и при совершении вызова. Здесь простая реализация:
var requestCount = 0;
$.ajax(url, {
dataType: 'jsonp',
requestCount: ++requestCount,
success: function(response, code) {
if (requestCount !== this.requestCount) return;
// if we're still here, this is the latest request...
}
});
Здесь я использую тот факт, что все, что вы передаете в $.ajax
, привязывается к объекту, который использовался как this
в обратном вызове.
Было бы неплохо, если бы jQuery сделал abort()
сделать это для нас, конечно.
jsonpString переопределяет имя функции обратного вызова в запросе jsonp. Это значение будет использоваться вместо "обратного вызова" в "обратном вызове =?" часть строки запроса в URL-адресе.
Итак, {jsonp:'onJSONPLoad'}
приведет к передаче 'onJSONPLoad=?'
на сервер. Начиная с jQuery 1.5, установка опции jsonp на false запрещает jQuery добавлять строку ?callback
к URL-адресу или пытаться использовать =?
для преобразования. В этом случае вы также должны явно установить параметр jsonpCallback
. Например, { jsonp: false, jsonpCallback: "callbackName" }
http://api.jquery.com/jQuery.ajax/
jQuery добавляет ?callback=jQuery17109492628197185695_1339420031913
, а затем устанавливает данные запроса как параметр для этого обратного вызова, поэтому у вас будет:
jQuery17109492628197185695_1339420031913({
"status": 200,
"data": {your json}
})
Чтобы избежать установки дополнительных параметров для запроса URL-адреса и вызова обратного вызова, добавьте этот параметр в метод ajax: jsonp:false
, поэтому он будет выглядеть следующим образом:
$.ajax({
...
jsonp:false,
...
});
Не прерывайте запрос
Просто сохраните где- нибудь объект jqXHR, возвращенный $.ajax()
theJqXHR = $.ajax(....
Если пользователь отменяет запрос на ноль сохраненного объекта
// user canceled
theJqXHR = null;
Наконец, когда вы получите ответ (success
обратный вызов), обратный вызов сравнит объект jqXHR ответа с сохраненным объектом.
function successCallback(data, textStatus, jqXHR )
{
if( theJqXHR !== jqXHR )
{
// user canceled; discard the response
return;
}
// process the response
}
Нет ошибок JQuery.
В качестве общего совета не полагайтесь на abort()
, даже для регулярных запросов AJAX.
В любом случае вы не сохраните ресурс на сервере, поскольку отправленный вами запрос будет обработан, и остановить его невозможно. И ответ вернется.
Некоторые (старые) браузеры обрабатывают abort()
неправильно.
Просто "кэшируйте" объект jqXHR и обработайте сценарий CANCEL самостоятельно.
Тревор Бернэм отвечает довольно хорошо, но вместо отслеживания количества запросов вы должны просто сравнить запрос с параметром XHR, например:
doRequest: function() {
this._freeRequest();
this._request = $.getJSON(url + params + '&callback=?', function(response, status, xhr) {
if (this._request !== xhr) return; // aborted
// success
}.bind(this)).done(this._freeRequest.bind(this));
}
_freeRequest: function() {
if (this._request) {
delete this._request;
}
}
Вызов doRequest
снова или _freeRequest
один раз до того, как предыдущий запрос будет завершен, приведет к "аборту" указанного запроса, заставив строку if (this._request !== xhr)
стать истинной, поскольку this._request
будет либо удалена, либо другой запрос вообще.