Abort JSONP ajax request with jQuery

2019-02-02 15:11发布

I'm using a JSONP ajax call to load some content from a different domain, and all this stuff is executed if the user causes a "mouseover" on a button.

I can capture the $.ajax() call return as a xhr object, and use it to abort the ajax request each time the user causes a "mouseover". But the JSONP callback function still gets called, and this causes an error, and I think it is beacuse the xhr.abort() method does not prevent the callback function to be called.

I've tried surrounding the $.ajax() call with try{}catch(e){}, but after I call the xhr.abort() method, the error continues.

Is there a way to handle that exception?

The raised exception is like this (according to Firebug): jQuery16102234208755205157_1308941669256 is not a function

And the exception's internal structure is like this: jQuery16102234208755205157_1308941669256({... my json data from a different domain....})

5条回答
beautiful°
2楼-- · 2019-02-02 15:38

The basic answer is simply the one given here: You can't really abort() a JSONP call. So the real question is, how do you avoid both superfluous callback invocations and the error you're seeing?

You can't use try...catch around the callback because it's asynchronous; you'd have to catch it from jQuery's end, and jQuery generally doesn't handle exceptions thrown from callbacks. (I discuss this in my book, Async JavaScript.) What you want to do instead is use a unique identifier for each Ajax call and, when the success callback is invoked, check whether that identifier is the same as it was when you made the call. Here's an easy implementation:

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...
  }
});

Here I'm taking advantage of the fact that anything you pass to $.ajax is attached to the object that's used as this in the callback.

It'd be nice if jQuery made abort() do this for us, of course.

查看更多
趁早两清
3楼-- · 2019-02-02 15:41

jsonpString overrides the callback function name in a jsonp request. This value will be used instead of 'callback' in the 'callback=?' part of the query string in the URL.

So {jsonp:'onJSONPLoad'} would result in 'onJSONPLoad=?' passed to the server. As of jQuery 1.5, setting the jsonp option to false prevents jQuery from adding the ?callback string to the URL or attempting to use =? for transformation. In this case, you should also explicitly set the jsonpCallback setting. For example, { jsonp: false, jsonpCallback: "callbackName" }

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

jQuery adds ?callback=jQuery17109492628197185695_1339420031913 and later sets the request data as parameter to this callback, so you will have:

jQuery17109492628197185695_1339420031913({
  "status": 200,
  "data": {your json}
})

To avoid setting additional parameters to request a URL and calling callback, add this parameter to ajax method: jsonp:false, so it will be look like:

$.ajax({
  ...
  jsonp:false,
  ...
});
查看更多
Luminary・发光体
4楼-- · 2019-02-02 15:43

Trevor Burnham's answer is pretty good, but instead of tracking a request count, you should just compare the request to the XHR parameter, like so;

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;
    }
}

Calling doRequest again or _freeRequest once before the previous request has completed, will result in the "abortion" of said request by causing the if (this._request !== xhr) line to become true, since this._request will either be deleted or another request altogether.

查看更多
趁早两清
5楼-- · 2019-02-02 15:50

In jQuery 1.5 all the Ajax APIs have a wrapper object around the native XHR objects. Take a look at:

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

 jqxhr.abort(); // should be what you're looking for
查看更多
祖国的老花朵
6楼-- · 2019-02-02 16:04

Do not abort the request

Just store somewhere the jqXHR object returned by $.ajax()

theJqXHR = $.ajax(....

If the user cancel the request null the saved object

// user canceled
theJqXHR = null;

Finally when you receive the response (success callback) the callback will compare the jqXHR object of the response with the saved object.

function successCallback(data, textStatus, jqXHR )
{
    if( theJqXHR !== jqXHR )
    {
        // user canceled; discard the response
        return;
    }

    // process the response
}

No jQuery errors.


As a general advice don't rely upon abort(), even for regular ajax requests.

  1. In any case you won't save resource on the server bacause the request you sent will be processed and there is no way to stop it. And a response will come back.

  2. Some (older) browsers handle abort() not properly.

Just "cache" the jqXHR object and handle the CANCEL scenario yourself.

查看更多
登录 后发表回答