简体   繁体   中英

Ajax complete is fired before success is ready, how can one prevent this behaviour?

I have an AJAX request which fetches a chunk of HTML which I insert into the DOM. While this is happening I am showing a spinner loading gif.

I want the spinner to hide at the exact same time as the data received from the ajax request is inserted into the DOM.

The problem is that the javascript starts executing the complete part before the HTML is actually inserted into the DOM. So for the end user the spinner goes away and a while after, the DOM pops up.

 $('#mySpinner').show();
 $.ajax({
     success: function(data) {
         $('#myElement').html(data);
     },
     complete:(){
         $('#mySpinner').hide(); // This is called when the success part is still executing
     }
 });

EDIT: I'm not saying complete is fired before success. I am saying complete is fired before success is ready . So the order in what happens is this:

  1. Success is called
  2. $('#myElement').html(data); is called
  3. Complete is called
  4. $('#mySpinner').hide() is called
  5. $('#mySpinner').hide() is finished
  6. $('#myElement').html(data); is finished

Just do this then :

$('#mySpinner').show();
$.ajax({
    success: function(data) {
     $('#myElement').html(data);
     $('#mySpinner').hide();
 }

});

But the behaviour you describe is not inline with jQuery doc as complete should only occur after success and error ... can you reproduce this wrong behaviour in a jsFiddle ? It might be the problem is somewhere else...

html() runs synchronously, however the browser could still be rendering when the next statement is executed. You could try to add a simple setTimeout to give the browser time to display the added content:

$('#mySpinner').show();
$.ajax({
    success: function(data) {
        $('#myElement').html(data);
        setTimeout(function() {
            $('#mySpinner').hide();
        }, 0);
    },
    error: function() {
        $('#mySpinner').hide();
    } 
});

Another option is to add a specific element to the added html and only continue when that element exists:

function waitForDom(el, cb) {
    if ($(el).length) {
        $(el).remove();
        cb();
        return;
    }

    setTimeout(function() {
        waitForDom(el, cb);
    }, 10);
}

$('#mySpinner').show();
$.ajax({
    success: function(data) {
        $('#myElement').html(data + '<div id="waitForDom"></div>');

        waitForDom("waitForDom", function() {
            $('#mySpinner').hide();
        });
    },
    error: function() {
        $('#mySpinner').hide();
    } 
});

You can simply hide your spinner in success part of ajax code:

$('#mySpinner').show();
 $.ajax({
     success: function(data) {
         $('#myElement').html(data);
         $('#mySpinner').hide();
     }
 });

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM