简体   繁体   中英

Jquery : Set delay for each iteration

Suppose this is the logic that I want :

// On fail return status = 500, else success will return PDF bytestream
function request() {
  return $.ajax({
            url: url,
            async:false,
            // other properties
        });
}

$('#action').click(function(e) {  

    $("#loading").fadeIn("slow"); // display loading

    while(true) {
        if(request().status != 200) {
            delay(3000);
        } else { break; }
    }

    $("#loading").fadeOut("slow"); // hide loading
});

For testing delay without iteration and request, this code works well :

    $(document).ready(function(){
        $('#action').click(function(e) {  
            $("#loading").fadeIn("slow");
            setTimeout(function() {
                $("#loading").fadeOut("slow");
            }, 5000);
            e.preventDefault();
        });
    });

Problem started when I put some loops and request inside, like this :

    var isOk;
    $(document).ready(function(){
        $('#action').click(function(e) {  

            $("#loading").fadeIn("slow");

            while(true) {
                request().always(function(jqXHR){
                    console.log(jqXHR);
                    if(jqXHR.status == 500) {
                        isOk = false;
                        setTimeout(function(){console.log("False")}, 3000);
                    } else { isOk = true; }
                });

                if(isOk) {break};
            }

            $("#loading").fadeOut("slow");
            e.preventDefault();
        });
    });

It's like there's no delay in between iteration. The loading symbols fadeIn and fadeOut instantly. Any idea how to do the correct delay for iteration ?

Use promises (technically, jQuery Deferred in this example but same concept) to fix the flow, and save yourself a lot of headache:

$('#action').click(function(e) {  
  $('#loading').fadeIn('slow'); // display loading
  $.ajax(url).always(function (e) {
    $('#loading').fadeOut('slow'); // hide loading
  });
});

Note that I'm using .always() ... that way even if there's an error, we'll still hide the loading indicator. You can add another handler for .fail() to catch errors.

Even better yet, use .show() and .hide() , and use CSS animations for any fading styling like this. While unlikely to matter much in this case, it makes these transitions extremely optimized in the browser engine, out of the JavaScript, while separating your application logic from styling even more.

You should call .fadeOut() when ajax request is resolved, like this:

$(document).ready(function(){

    $('#action').click(function(e) { 
        e.preventDefault(); 

        $("#loading").fadeIn("slow");

        performRequest();

    });

    function performRequest() {

            request()
                .always(function(jqXHR){
                    console.log(jqXHR);

                    if(jqXHR.status === 500) {
                       console.log("False");
                       var t = setTimeout(function() { 
                           performRequest();    // retry after 3sec.
                           clearTimeout(t);
                       }, 3000);
                    } else { 
                       onRequestSuccess(); // success
                    }
            });
    }

    function onRequestSuccess() {
         $("#loading").fadeOut("slow");
    }

});

Since the ajax call is asynchronous , it doesn't wait before executing the next line of code.

If you want to fadeOut on finish, run fadeOut() inside the callback function of the ajax call, or within this function .

Put the following right where you have //other properties :

complete: function(jqXHR, textStatus) {
  $("#loading").fadeOut("slow");
}

You have to use delay() , setTimeout() otherwise.

Delay:

$("#loading").fadeIn(2000);
$("#loading").delay(2000).fadeOut(2000);

setTimeout:

$("#loading").fadeIn(2000);
setTimeout(function(){
  $("#loading").fadeOut(2000);
}, 2000);

Just another suggestion, handle errors in your Ajax call, rather than in while loops:

error: function(jqXHR, textStatus, errorThrown) {
  setTimeout(function() {
    request();
  }, 3000);
}

And another, take @Brad 's advice and use CSS Animations instead.

Here is what I was talking about. In this example, the fadeOut is executed after fadeIn is done as a callback. I included a timeout to show you can do that as well.

 $(function() { $("#test").fadeIn(2000, function() { setTimeout(function() { $("#test").fadeOut(2000); }, 1000); }); });
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <div id="test" style="display:none"> TEST DIV </div>

If you want the loading to fade in before each ajax call and fade out after success, then you'll need to handle the fade out in your ajax success callback. Using your code, this would fade out upon completion.

$(document).ready(function(){
    $('#action').click(function(e) {  

        $("#loading").fadeIn("slow");

        while(true) {
            request().always(function(jqXHR){
                console.log(jqXHR);
                if(jqXHR.status == 500) {
                  setTimeout(function(){console.log("False")}, 3000);
                } else { 
                    $("#loading").fadeOut("slow");
                    break;
                }
            });
        }            
        e.preventDefault();
    });
});

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