jQuery When, abort multiple Ajax

2019-07-16 06:22发布

问题:

How can a jQuery when deferred object which has multiple Ajax calls be stopped (aborted), so any pending Ajax calls will not be called?

Example code (minimal):

var deferred = $.when(
  $.getJSON( "a.json" ),
  $.getJSON( "b.json" )
)
.done(( res )=>{
  // whatever...
});
// abort the all AJAX calls after N miliseconds
setTimeout(()=>{ deferred.abort() }, 2000);

But of course, one cannot simply do deferred.abort() since the abort method does not exist.

回答1:

This isn't a feature of the promise you get back from $.when. You can readily write it yourself, though: (See below for an alternative, though.)

function whenWithAbort(...xhrs) {
    return {
        abort() {
            xhrs.forEach(xhr => {
               xhr.abort();
            });
        },
        promise: $.when(...xhrs)
    };
}

Usage:

var ops = whenWithAbort(
  $.getJSON( "a.json" ),
  $.getJSON( "b.json" )
)
.promise.done(( res )=>{
  // whatever...
});
// abort the all AJAX calls after N miliseconds
setTimeout(()=>{ ops.abort() }, 2000);

Or actually, more generically, just a when-with-array:

function whenPlus(...list) {
    return {
        list,
        promise: $.when(...list)
    };
}

Then:

var ops = whenWithAbort(
  $.getJSON( "a.json" ),
  $.getJSON( "b.json" )
)
.promise.done(( res )=>{
  // whatever...
});
// abort the all AJAX calls after N miliseconds
setTimeout(()=>{ ops.list.forEach(op => { op.abort() } }, 2000);

Or you could give it a method that calls a named method on all entries:

function whenPlus(...list) {
    return {
        list,
        callOnEach(method) {
            list.forEach(entry => { entry[method]() });
        },
        promise: $.when(...list)
    };
}

Then:

var ops = whenWithAbort(
  $.getJSON( "a.json" ),
  $.getJSON( "b.json" )
)
.promise.done(( res )=>{
  // whatever...
});
// abort the all AJAX calls after N miliseconds
setTimeout(()=>{ ops.callOnEach("abort") }, 2000);


回答2:

I ended up doing:

var ajaxCalls = [
    $.getJSON( "a.json" ),
    $.getJSON( "b.json" )
];

$.when(...ajaxCalls)
    .done(( res )=>{
      // whatever...
    });

// abort the all AJAX calls after N miliseconds
setTimeout(()=>{ ajaxCalls.forEach(a => a.abort()) }, 2000);

Too bad the when method result doesn't also exposes the list of arguments supplied to it, so it could be accessed directly (and aborted in this case).