javascriptajaxasynchronous

Question about synchronous ajax call in JS


With below code, what I was expecting is "diameter-selected" class to be added to the button and then to run the synchronous ajax calls. But, it seems that ajax calls run before the ".addClass" command and since it is waiting the promise I guess, I see the button effect after ajax request is completed. When I added setTimeout to the ajax calls for 1 nano second, I see the button effect before ajax calls are completed. So, I solved my issue in a weird way but I want to learn if there is a more professional way to achieve this.

    $(document).on("click", ".btn-diameter", function(){

       $(this).addClass("diameter-selected");

       $.ajax({
         method: "POST",
         async: false,
         url: "/page1.asp"
       });

       $.ajax({
         method: "POST",
         async: false,
         url: "/page2.asp"
       });

    });     

Solution

  • This is because your requests with async: false block main browser's thread. That's why it won't re-render an element with a new css class until your synchronical requests are fulfilled.

    So, just replace your code with this (in order to save synchronicity you should use success callback):

      $(document).on("click", ".btn-diameter", function(){
    
        $(this).addClass("diameter-selected");
        
        
        $.ajax({
            method: "POST",
            url: "/page1.asp",
            success: function() {
                $.ajax({
                    method: "POST",
                    url: "/page2.asp"
                });
            }
        });
        
    }); 
    

    Btw I use success instead of done, according to jquery docs (https://api.jquery.com/jQuery.ajax/)

    As of jQuery 1.8, the use of async: false with jqXHR ($.Deferred) is deprecated; you must use the success/error/complete callback options instead of the corresponding methods of the jqXHR object such as jqXHR.done()

    However, it is better to use Promises instead like this:

    $(document).on("click", ".btn-diameter", function(){
        $(this).addClass("diameter-selected");
        fetch("/page1.asp", { method: "POST" })
            .then(() => fetch("/page2.asp", { method: "POST" }))
    });