Прервать запрос JSONP ajax с помощью jQuery

Я использую вызов JSONP ajax для загрузки некоторого контента из другого домена, и все это выполняется, если пользователь вызывает «наведение мыши» на кнопку.

Я могу зафиксировать возврат вызова $.ajax() как объект xhr и использовать его для прерывания запроса ajax каждый раз, когда пользователь вызывает «наведение мыши». Но функция обратного вызова JSONP по-прежнему вызывается, и это вызывает ошибку, и я думаю, что это связано с тем, что метод xhr.abort() не предотвращает вызов функции обратного вызова.

Я пытался окружить вызов $.ajax() с помощью try{}catch(e){}, но после вызова метода xhr.abort() ошибка сохраняется.

Есть ли способ обработать это исключение?

Возникшее исключение выглядит следующим образом (согласно Firebug): jQuery16102234208755205157_1308941669256 не является функцией

А внутренняя структура исключения такова: jQuery16102234208755205157_1308941669256({... мои данные json из другого домена....})


person David    schedule 24.06.2011    source источник
comment
возможный дубликат Убить запросы ajax с помощью javascript с помощью jquery.   -  person Naftali aka Neal    schedule 24.06.2011
comment
Я предполагаю, что это не тот дубликат, потому что этот вопрос касается предотвращения исключения после вызова метода jqxhr.abort() в запросе ajax JSONP, а не о том, как остановить сам запрос.   -  person David    schedule 01.07.2011
comment
Ответ на этот вопрос можно найти в дублирующем вопросе stackoverflow.com/questions/9533848/   -  person Trevor Burnham    schedule 03.04.2012
comment
очень старый вопрос. сегодня наткнулся на такую ​​же проблему. Я добавил свой вклад. Я не знаю, заслуживает ли мой ответ быть принятым, но наверняка принятый ответ не должен быть текущим (отклоненным)   -  person Paolo    schedule 06.12.2016


Ответы (5)


В jQuery 1.5 все API-интерфейсы Ajax имеют объект-оболочку вокруг собственных объектов XHR. Взгляни на:

http://api.jquery.com/jQuery.ajax/#jqXHR

 jqxhr.abort(); // should be what you're looking for
person Declan Cook    schedule 24.06.2011
comment
Это то, что я использую прямо сейчас. Это прерывает запрос ajax. Но этот запрос ajax использует JSONP. После того, как я использую метод abort(), вызывается функция javascript, созданная внутри jQuery для обработки ответа JSONP, но метод прерывания, похоже, удаляет определение этой функции или что-то в этом роде, потому что есть исключение, которое я не смог обрабатывать. - person David; 27.06.2011
comment
У вас есть дополнительная информация? живой пример, сообщение об исключении? - person Declan Cook; 27.06.2011

Основной ответ — тот, что дан здесь: вы не можете abort() вызвать JSONP. Итак, реальный вопрос заключается в том, как избежать как лишних вызовов обратного вызова, так и ошибки, которую вы видите?

Вы не можете использовать try...catch вокруг обратного вызова, потому что он асинхронный; вам придется перехватывать его с конца jQuery, а jQuery обычно не обрабатывает исключения, вызванные обратными вызовами. (Я обсуждаю это в своей книге Асинхронный 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() сделать это за нас.

person Trevor Burnham    schedule 03.04.2012

Не отменять запрос

Просто сохраните где-нибудь объект jqXHR, возвращенный $.ajax()

theJqXHR = $.ajax(....

Если пользователь отменит запрос, null сохраненный объект

// 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.

  1. В любом случае вы не будете экономить ресурсы на сервере, так как отправленный вами запрос будет обработан и остановить его невозможно. И ответ придет.

  2. Некоторые (старые) браузеры неправильно обрабатывают abort().

Просто «кэшируйте» объект jqXHR и самостоятельно обработайте сценарий CANCEL.

person Paolo    schedule 06.12.2016
comment
Третий аргумент XHR никогда не соответствует объекту, возвращаемому $.ajax. - person Jack Cole; 13.12.2018
comment
@JackCole Я пытался, и на самом деле да, это так. Попробуйте это на консоли: jqxhr1=$.ajax({url: "/", success: function(data,status,jqxhr2){alert(jqxhr1===jqxhr2);}}) Я получаю true - person Paolo; 15.12.2018

jsonpString переопределяет имя функции обратного вызова в запросе jsonp. Это значение будет использоваться вместо callback в callback=? часть строки запроса в 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,
  ...
});
person Alex    schedule 14.06.2012

Ответ Тревора Бернхэма довольно хорош, но вместо отслеживания количества запросов вы должны просто сравнить запрос с параметром 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 будет либо удален, либо вообще будет другой запрос.

person Kevin Jurkowski    schedule 16.06.2014