Drag the user interface into Webkit (Safari & Chrome) right before the synchronous "Ajax" request

On a simple Ajax website, we make several HttpRequests requests synchronously (I understand that synchronous Ajax is a bit of an oxymoron). The main reason this is done synchronously and asynchronously is to simplify the programming model for some of those involved (long story).

In any case, we want to be able to change the style (in particular, impose a screen with a translucent white color, as a Google search does) immediately before the request, and then remove it when the results are returned. Essentially, it looks like this:

load:function(url) { .... busyMask.className="Shown"; //display=block; absolute positioned full screen semi-transparent var dta=$.ajax({type:"GET",dataType:"json",url:url,async: false}).responseText; busyMask.className="Hidden"; //sets display=none; ... return JSON.parse(dta); } 

Synchronous requests are known to block the user interface. So it is not surprising that the white overlay never appears in Safari and Chrome (this is interesting in Firefox). I tried to slow down the response with the pink overlay so that it was painfully obvious, but it just won’t refresh the user interface until the request is complete. Leaving "busyMask.className =" Hidden ", the part will display the mask, but only after the completion of the ajax request.

I saw many tricks to get the user interface to redraw (for example, Why does HourGlass not work with synchronous AJAX request in Google Chrome ? , http://ajaxian.com/archives/forcing-a-ui-redraw-from-javascript ), but they all seem to be related to trying to show the actual “persistent” DOM or style updates, rather than temporarily display a style change while a synchronous request.

So is there a way to do this, or am I fighting a lost battle? Perhaps we just need to switch to asynchronous queries in each case for the worst executable queries, which may be a decent way to solve the learning curve problem ... But I hope there is an external answer here.

+6
source share
4 answers

Good for this question, I will ignore the excuse for why you need synchronous XHR requests. I understand that sometimes working constraints do not allow the use of a best practice solution, and therefore we “do” to do the work. So let's focus on how to get a synchronous ajax with a visual update that works for you!

Well, given that you are using jQuery for your XHR query, I am going to use it to use jQuery to show / hide the progress bar and handle any time issues.

First, configure the download indicator in our markup:

 <div id="loading" style="display:none;">Loading...</div> 

Now create some javascript:

 // Show the loading indicator, then start a SYNCRONOUS ajax request $('#loading').show().delay(100).queue(function() { var jqxhr = $.ajax({type:"GET",dataType:"json",url:"www.yoururl.com/ajaxHandler",async: false}).done(function(){ //Do your success handling here }).fail(function() { //Do your error handling here }).always(function() { //This happens regardless of success/failure $('#loading').hide(); }); $(this).dequeue(); }); 

First, we want to show our loading indicator, and then give the browser an instant delay for redrawing before our synchronous XHR request starts. Using the jQuery .queue() method, we put our .ajax() call in the default fx queue so that it does not execute until .delay() , which of course does not happen until after .show() .

The jQuery .show() method changes the display style of the style of the .show() element to block (or restores its initial value, if assigned). This change in CSS will cause the browser to overpay (aka redraw) as soon as it can. The delay ensures that he can complete the payment before calling ajax. The delay is not needed in all browsers, but it will not hurt more than the number of milliseconds you specified (as usual, IE will be the limiting factor here, other browsers are happy with the 1 ms delay, IE wanted something a little more significant for repainting) .

Here's jsfiddle for testing in multiple browsers: jsfiddle example

+4
source

Why do you think:

 doSomethingBeforeRequest(); response = synchronousAjax(); doSomethingToTheDataAfterRequest(response); 

which is much "simpler" than:

 doSomethingBeforeRequest(); properAjax(onSuccess(response){ doSomethingToTheDataAfterRequest(response); }; 

for your team? I'm not trying to argue, but I'm seriously interested in an excuse ...

The only advantage of synchronous code that I can think of is that you keep multiple curly braces; due to freezing the browser.

If the browser does not complete the redraw before the request *, the only option I can think of is to use a delay (as BenSwayne suggests); which will make the code as complex as an asynchronous call, and still make the browser immune during the request.

EDIT (some kind of answer):

Since JavaScript lacks threads; timeouts and ajax calls (which allows the browser to do something even before it starts, unlike sleep () in a streaming language), is quite fundamental for how you program JavaScript. I know that at first there may be a bit of a learning curve (I know that I was confused), but there is no reasonable way to avoid studying it.

One of the situations where I know that people may be tempted to make synchronous calls is that multiple requests must be sent to the server sequentially; but you can also do this asynchronously by entering a few such calls:

 doSomethingBeforeRequest1(); ajax(onSuccess(response1){ doSomethingToTheDataAfterRequest1(response1); ajax(onSuccess(response2){ doSomethingToTheDataAfterRequest2(response2); }; }; 

But if each call ends rather slowly, and you want to indicate progress at each step or something else; I would prefer that you create a new service to combine two operations with one call. (This service can simply use the two existing services in sequence if you still need them separately in some other cases.)

(* I am more surprised that Firefox is updating dom ...)

0
source

I did some tests and came up with some points: http://jsfiddle.net/xVHWs/1/

Change your code to use jQuery hide() , show() or animate({ opacity: 'show' }, 'fast') and animate({ opacity: 'hide' }, 'fast') if you leave functions without a temporary parameter or specify a time of 0 ms, Firefox will show the overlay and hide it, other browsers will execute it quickly so you can see. Put 100 milliseconds in show , hide or animate and you will see it.

0
source
 $.ajaxSetup({async:false}); busyMask.className="Shown"; //display=block; absolute positioned full screen semi-transparent var dta=$.ajax({type:"GET",dataType:"json",url:url}).responseText; busyMask.className="Hidden"; //sets display=none; $.ajaxSetup({async:true}); 
-1
source

Source: https://habr.com/ru/post/900958/


All Articles