Chrome and Safari ajax issue with async:false

338
January 30, 2017, at 06:16 AM

I saw this everywhere on the web but i couldn't manage to fix my code to avoid this issue, simply I have an ajax function that I trigger when some buttons are clicked, sometimes I want an indicator (loading animation) to show, sometimes not, so i build my function:

function doAjax(action, todo, items, error_num, hide_indicator) {
  items.action = action;
  items.do = todo;
  var postedObj;
  $.ajax({
    type: 'post',
    dataType: 'html',
    url: ajaxURL,
    data: items,
    async: false,
    beforeSend: function() {
      if (!hide_indicator) showIndicator();
    },
    success: function(data) {
      if (data) {
        ajaxObj = JSON.parse(data);
        if (ajaxObj.ok) {
          postedObj = ajaxObj;
        } else {
          alert(ajaxObj.error);
          postedObj = false;
        }
      } else {
        alert('[' + error_num + '] Something went wrong.');
        postedObj = false;
      }
      if (!hide_indicator) hideIndicator();
    },
    error: function() {
      alert('[' + error_num + '] Something went wrong.');
      postedObj = false;
      if (!hide_indicator) hideIndicator();
    }
  });
    return postedObj;
}

And here is what I do on my buttons to call the function:

$(document).on('click', '.ad-single', function() {
  var addataObj = doAjax('post_requests', 'get-ad-info', {"id": $(this).data('ad')}, '158', false); // false means DON'T hide the indicator
  if (addataObj) {
    loadContent(addataObj.ad);
  }  
});

OK, for now, everything works as expected on Firefox, when I click my button, the indicator shows up and wait until data is returned by ajax, then hide the indicator again.

This doesn't work on Chrome and Safari, the function works fine and return the data as expected but it seems that the hideIndicator() function is called immediately, I couldn't know how to fix this.

Firefox:

Chrome and Safari:

Answer 1

Using async: false is evil. The Internet is full of such posts, and many browsers including Chrome and Safari will give you numerous warnings on making synchronous AJAX requests.

Fortunately, jQuery's promises can be used to overcome your problem. It doesn't change how your function works, and leverages the power of promises too to make async requests.

You can modify your existing function as follows, so that it returns an AJAX promise, instead of the result.

function doAjax(action, todo, items, error_num, hide_indicator) {
  items.action = action;
  items.do = todo;
  return $.ajax({
      type: 'post',
      dataType: 'html',
      url: ajaxURL,
      data: items,
      beforeSend: function() {
        if (!hide_indicator) showIndicator();
      }
    })
    .then(function(data) {
      if (!hide_indicator) {
        hideIndicator();
      }
      if (data) {
        ajaxObj = JSON.parse(data);
        if (ajaxObj.ok) {
          return ajaxObj;
        }
        alert(ajaxObj.error);
        return false;
      }
      alert('[' + error_num + '] Something went wrong.');
      return false;
    }, function() {
      if (!hide_indicator) {
        hideIndicator();
      }
      alert('[' + error_num + '] Something went wrong.');
      return false;
    });
}

Here, a .then function can be used to pre-process the response, and return the appropriate value to the subsequent promise handlers.

A subsequent promise handler can be implemented as follows, which calls the doAjax function, and reacts on the value returns by pre-processing.

$(document).on('click', '.ad-single', function() {
  doAjax('post_requests', 'get-ad-info', {"id": $(this).data('ad')}, '158', false)
    .then(function(addataObj) {
      if (addataObj) {
        loadContent(addataObj.ad);
      }
    });
});

Here, the .then() chains up with the previous .then(), and reacts on the value returned (which is received in addataObj). Note that it only reacts on the success of the AJAX call. If you want to handle the error response as well, you need to pass a second argument as a function to the .then() handler.

Hope this solves your problem.

Answer 2

In this question, you can find the answer. Try to remove async: false

READ ALSO
jQuery(…).select2 is not a function?

jQuery(…).select2 is not a function?

I have included a theme in my yii projectIn a view i used yii select2 extension but i am getting error

539
how to render events? fullcalendar js

how to render events? fullcalendar js

I'm working with fullcalendarjs library and would like to know:

462
How to get all checked nodes in bootstrap tree-view

How to get all checked nodes in bootstrap tree-view

I am using boostrap treeview, https://githubcom/jonmiles/bootstrap-treeview, and i don't know how to get all checked nodes

529
Render days in different colours on month view based on number of events

Render days in different colours on month view based on number of events

i want to check how many events exists in a day and depending on that quantity, render the given day with another color in month view

244