1

I'm confused by this synchronous jquery ajax request. The ajax loader doesn't show until after the ajax call is complete. I'm well aware that the synchronous request will block the UI, but why does it start blocking before that line of code has been hit? I must be misunderstanding something fundamental about execution order.

            $("#ajax-loader").show(1, function(){
                $.ajax({
                    url: xxx,
                    type: "POST",
                    async: false,
                    success: function (data) {
                        hideAjaxLoader();
                    }
                });
            });
centralscru
  • 6,580
  • 3
  • 32
  • 43
  • 1
    It should by asynchronous if you don't want to block the UI. Just remove `async: false` and it will work. – Reinstate Monica Cellio Oct 27 '16 at 09:45
  • Because it's synchronous?! Generally you should never use `async:false` – Liam Oct 27 '16 at 09:45
  • 1
    Possible duplicate of [What does "async: false" do in jQuery.ajax()?](http://stackoverflow.com/questions/1478295/what-does-async-false-do-in-jquery-ajax) – Liam Oct 27 '16 at 09:46
  • 2
    You just must note that DOM will be rendered (your loader will be shown) after **all current synchronous code** will be executed. That is why loader not shown before request. – Andrey Oct 27 '16 at 09:47
  • 1
    @Liam: See the question -- the OP is clearly aware of that. The question is why is it preventing the loader from showing when in theory it's called **after** the loader is showing. – T.J. Crowder Oct 27 '16 at 09:47
  • @Andrey: See my comment above to Liam. – T.J. Crowder Oct 27 '16 at 09:47
  • @T.J.Crowder, yes, and I'm answering exactly why – Andrey Oct 27 '16 at 09:49
  • @Andrey: Note where the ajax call is: In the *completion handler* of an animation. E.g., called later, in theory when the animation is complete. – T.J. Crowder Oct 27 '16 at 09:51

1 Answers1

8

Even though jQuery believes the animation is complete when it calls your code containing the synchronous ajax call, that doesn't mean the browser has done all of its work to render the result before that callback. And since most browsers completely block their UI during a synchronous ajax call, it doesn't get around to it until later.

Obviously, wherever possible, just don't use synchronous ajax, since it has this behavior of blocking the UI.

But, if you absolutely cannot avoid making it synchronous (I've never encountered a valid example of such a situation; I'm told they exist), add a brief delay after jQuery thinks the animation is done before starting your ajax. Firefox in particular seems to want a fair bit of time:

$("#ajax-loader").show(1, function(){
    setTimeout(function() {
        $.ajax({
            url: xxx,
            type: "POST",
            async: false,
            success: function (data) {
                hideAjaxLoader();
            }
        });
    }, 50); // 50 ms
});

Again, I strongly recommend not using synchronous ajax, but if you need to, just delay the onset.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • 1
    Thanks very much, that's a good explanation. I was wrongly assuming that jQuery's idea of "finished" would match the browser but evidently that's where I'm going wrong. – centralscru Oct 27 '16 at 11:19
  • 1
    In case it's of interest, our reason for using synchronous here is only semi valid. We need to make a change to a function that's called from many places in the code. To use an asynchronous request would necessitate reworking all the calls to include a callback. That would in turn necessitate a large amount of manual tests before the change can be released. Making the request synchronous means we don't have to add the callbacks in order to make the change, and therefore don't have to do those retests. Obviously the architecture is the real problem here. – centralscru Oct 27 '16 at 11:22
  • Great explanation! – Amiga500 Oct 27 '16 at 16:04