最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - jQuery - set Ajax handler priority - Stack Overflow

programmeradmin3浏览0评论

actually the question is as simple as the topic says. Is there any way to give different ajax handlers a higher/lower priority (which means here, that they will fire earlier) ?

What do I mean? Well, I have to deal with a fairly huge web-app. Tons of Ajax requests are fired in different modules. Now, my goal is to implement a simple session-timeout mechanism. Each request sends the current session-id as parameter, if the session-id is not valid anymore, my backend script returns the request with a custom response-header set (value is a uri).

So I'm basically going like this

window.jQuery && jQuery( document ).ajaxComplete(function( event, xhr, settings ) {
    var redirectto = xhr.getResponseHeader( 'new_ajax_location' );
    if( redirectto ) {
        location.href = redirectto;
    }
});

This does work like a charm of course, but my problem is that this global ajax event actually needs to get fired first 100% of the time, which is not the case. Some of those original ajax-requests handlers will throw an error because of missing or unexpected data, in that case, the global handler never gets executed.

Now, I'd be kinda happy if I wouldn't need to go through every single request handler and make it failsafe for invalid session data responses. I'd much more prefer to do the job at one particular place. But how can I make sure my global handler will get executed first ?

actually the question is as simple as the topic says. Is there any way to give different ajax handlers a higher/lower priority (which means here, that they will fire earlier) ?

What do I mean? Well, I have to deal with a fairly huge web-app. Tons of Ajax requests are fired in different modules. Now, my goal is to implement a simple session-timeout mechanism. Each request sends the current session-id as parameter, if the session-id is not valid anymore, my backend script returns the request with a custom response-header set (value is a uri).

So I'm basically going like this

window.jQuery && jQuery( document ).ajaxComplete(function( event, xhr, settings ) {
    var redirectto = xhr.getResponseHeader( 'new_ajax_location' );
    if( redirectto ) {
        location.href = redirectto;
    }
});

This does work like a charm of course, but my problem is that this global ajax event actually needs to get fired first 100% of the time, which is not the case. Some of those original ajax-requests handlers will throw an error because of missing or unexpected data, in that case, the global handler never gets executed.

Now, I'd be kinda happy if I wouldn't need to go through every single request handler and make it failsafe for invalid session data responses. I'd much more prefer to do the job at one particular place. But how can I make sure my global handler will get executed first ?

Share Improve this question edited Jan 16, 2012 at 13:29 jAndy asked Jan 16, 2012 at 13:23 jAndyjAndy 236k57 gold badges311 silver badges363 bronze badges 5
  • Probably by using the onSuccess callback. – Stefan Commented Jan 16, 2012 at 13:27
  • @Stefan: I would need to catch all possible outes for a request, so plete is pretty fine. But I also checked to set success and error manually, unfortunately with the same behavior. – jAndy Commented Jan 16, 2012 at 13:35
  • Related to stackoverflow./questions/290254/…, since AJAX events are implemented using the core events system. – Frédéric Hamidi Commented Jan 16, 2012 at 13:45
  • @FrédéricHamidi: I'm not sure if that is related. Main problem here is, that a "global" ajax event handler is bound to the document instead a specific node. So, I can't even hack the data expando to modify function order. – jAndy Commented Jan 16, 2012 at 13:48
  • You could keep a boolean variable to see if the global ajax was executed and then allow other ajax calls? – chchrist Commented Jan 16, 2012 at 14:21
Add a ment  | 

4 Answers 4

Reset to default 1

If I understand you correctly, you want to add your own callback to json requests everywhere. You could use the ajaxPrefilter hook.

    $.ajaxPrefilter(function( options, originalOptions, jqXHR ) {
        options.plete = function (jqXHR2, settings) {
            var redirectto = jqXHR2.getResponseHeader( 'new_ajax_location' );
            if( redirectto ) {
                location.href = redirectto;
            }
        }
    });

You can also change the options there to add the session-id to the request params.

jQuery allows you to "patch" it's methods, such as .post/.ajax.

You might be able to patch the appropriate method(s) so your special AJAX event is always triggered before the one your code wants to call.

This is some "pseudo-jQuery-code" which should help you get started. I doubt it works as is, but it demonstrates the basic concept and it should get you started.

(function( $ ){
    var originalPost = $.post;
    var calledSpecialOne = false;
    $.post = function(url, data, success, dataType) {
        if (!calledSpecialOne) {
            originalPost( ... your special AJAX query ... ).then( function() {
            originalPost(url, data, success, dataType);
            }
            calledSpecialOne = true;
        } else {
            originalPost(url, data, success, dataType);
        }
    }
})( jQuery );

The above is based on some other, unrelated, code I have tested, which makes $.each() work for undefined/null arrays):

(function($){
    var originalEach = $.each;
    $.each = function(collection, callback) {
        return collection? originalEach(collection, callback) : [];
    }
 })(jQuery);

Note that many exposed functions are called internally by jQuery too, so be VERY carefull using this trick; you might break a different part of jQuery or cause other trouble. In case of the AJAX functions, you should probably patch the innermost function only, to prevent infinite recursion. (FWIW, I haven't found any side-effects for the $.each() patch so far).

I'm not sure if this is even what you meant, but I figured I might need it as some point anyway.

It patches jQuery's ajax function to accept an object with the property priority. If there isn't a priority set, its priority bees 1 (highest priority 0). If there is a priority, it does one of two things. If the priority is something like 5, it checks to see if the ajax call with the previous priority (in this case 4) was called. If not, it adds it to an array of ajax calls with that priority (in this case 5). If the previous priority has been called, it calls the request normally. When a request is called with a priority, it calls any outgoing requests with the next highest priority.

In other words, if there's no priority, it waits for priority 0, if there is a priority, it waits for the priority below it to get called. If you want calls with no priority to be sent immediately, ment out the line with the ment I put saying default action?

 (function( $ ){
        var oldAjax=$.ajax;
        var outgoing=[];
        var sent=[];
        $.ajax=function(url, settings) {
            var pr = (typeof url==='object'?url:settings).priority;
            pr = pr===undefined ? 1 : pr; // default action?
            if(pr!==undefined){
                if(pr==0 || sent[pr-1]!==undefined){
                    oldAjax(url,settings);
                    sent[pr]=true;
                    if(outgoing[pr]){
                        var rq=outgoing[pr].splice(0,1)[0];
                        $.ajax(rq[0],rq[1]);
                    }
                    if(outgoing[pr+1]){
                        var rq=outgoing[pr+1].splice(0,1)[0];
                        $.ajax(rq[0],rq[1]);
                    }
                }
                else{
                    if(outgoing[pr]!==undefined){
                        outgoing[pr].push([url,settings]);
                    }
                    else{
                        outgoing[pr]=[[url,settings]];
                    }
                }
            }
            else{
                oldAjax(url, settings);
            }
        };
    })( jQuery );

Patches for get and post. You will have to include those extra arguments, or change this yourself to get the priority working with post and get requests. This is straight from jQuery 1.7, except for the extra argument, and the two lines I added ments to.

    jQuery.each( [ "get", "post" ], function( i, method ) {
    jQuery[ method ] = function( url, data, callback, type, priority ) {
        // shift arguments if data argument was omitted
        if ( jQuery.isFunction( data ) ) {
            priority = type; // my change
            type = type || callback;
            callback = data;
            data = undefined;
        }

        return jQuery.ajax({
            type: method,
            url: url,
            data: data,
            success: callback,
            dataType: type,
            priority: priority // my change
        });
    };
});

I setup an example here: http://jsfiddle/tk39z/

I actually created some ajax requests targeting google, so you can check the network panel in Chrome to see the requests.

I recently implemented something very similar to the functionality that I believe you're looking for.

I set up a filter on the server side to test for a valid session and, if not, return a 401 error with custom status text for a more specific error detail.

The ajax calls I made to these pages were written in the normal convention using the 'success' attribute.

For situations where there was an error, I added a global callback to the error function that would test for the specific error and redirect accordingly. such as:

$( document ).ajaxError(function(e, xhr) {
    var redirectto = xhr.getResponseHeader( 'new_ajax_location' );
    if( redirectto ) {
        location.href = redirectto;
    }
});
发布评论

评论列表(0)

  1. 暂无评论