Bug Tracker

Opened 8 years ago

Closed 8 years ago

Last modified 8 years ago

#10286 closed enhancement (invalid)

AJAX prefilters and callbacks have no opportunity to influence Deferred object resolution

Reported by: dthm5kvf6e@… Owned by:
Priority: undecided Milestone: None
Component: unfiled Version: 1.6.4rc1
Keywords: Cc: jaubourg
Blocked by: Blocking:

Description

While I can supply success, error, and completion callbacks to any $.ajax() call, by the time these callbacks are invoked, the default AJAX transport object has already resolved or rejected the embedded promise/Deferred object on my behalf. Any code that was waiting on said resolution will be invoked whether I want it to or not.

The only way that I can pre-empt this behavior is by defining my own AJAX transport whose "send" method will receive a pointer to the default "done" method which performs this task. Since there is no way for such a custom transport to inherit or invoke the remainder of the default transport's logic without duplicating core library code, this is not a practical solution, either.

Change History (5)

comment:1 Changed 8 years ago by jaubourg

Cc: jaubourg added
Resolution: invalid
Status: newclosed

It's actually quite easy to override the promise behaviour of the jqXHR object in a prefilter. You just need to use the promise method of a new Deferred object with the jqXHR object itself as the target objet parameter:

$.ajaxPrefilter(function( options, originalOptions, jqXHR ) {
    var originalPromise = jqXHR.promise(),
        newDefer = $.Deferred(function( defer ) {
            defer.promise( jqXHR );
            jqXHR.success = defer.done;
            jqXHR.error = defer.fail;
            // Need a little bit more work to handle complete
        });
    originalPromise.done(function() {
        newDefer.resolve( /* whatever */ );
    });
});

Callbacks are not attached after prefilters are called so they will be attached to your new deferred this way. The jqXHR object hasn't been given to any external code yet (the beforeSend callback is called AFTER prefilters) so it's 100% safe.

comment:2 Changed 8 years ago by anonymous

Thanks. That's pretty ugly, though.

comment:3 in reply to:  2 Changed 8 years ago by jaubourg

Replying to anonymous:

Thanks. That's pretty ugly, though.

Well, let's see:

  • You don't have to know about the internals of the transport layer
  • You don't have to worry about the dataType conversion layer
  • You don't need to worry about another prefilter doing something similar (everything will still work as intended)

I'd say it's pretty neat in its simplicity. You could even do it using pipe:

jqXHR.pipe( function() {
   // Handle success and eventually redirect
}, function() {
   // Handle error and eventually redirect
} ).promise( jqXHR );
// Aliases
jqXHR.success = jqXHR.done;
jqXHR.error = jqXHR.fail;

Of course, you still have to handle complete if you really need to but that's not that much of an hassle, is it?

comment:4 Changed 8 years ago by anonymous

The API could make that process a whole lot less retarded by vending a reference to the internal "done" method, but that would involve actual thought in place of snark on your part, so I shant be holding my breath.

comment:5 Changed 8 years ago by jaubourg

Giving access to the internal "done" method (whatever you exactly mean by that) is insufficient and dangerous. A key in the design of Deferreds is to ensure no-one will bork your Deferreds to death. The fact that Deferreds methods are "detachable" (lexically bound) allows a lot of flexibility without the need to compromise the Deferred's internal state by having the Deferred's guts wide opened. Please, stop obsessing about your immediate problem and just ponder this for a mere second.

No, really, stop being mad at me/the screen/the world right now, re-read the paragraph above and do think about it.

I know it's always difficult to understand that cutting corners for every specific edge-case is NOT good design. Making so said edge-case can be solved using a reasonable amount of code without compromising everyone else's code (at least not that easily, I know we're still in JavaScript) is the ultimate goal.

Now bring on the insults!

Last edited 8 years ago by jaubourg (previous) (diff)
Note: See TracTickets for help on using tickets.