The UI thread blocking problem caused by synchronous Ajax was encountered and recorded here.
The reason is this, because there are several similar asynchronous request actions on the page, in line with the principle of increasing the reusability of code, I encapsulate a function called GetData, which receives different parameters, takes only the data and then return the data. The basic logic is stripped out of this:
function GetData1 () {
var result;
$.ajax ({
URL: "p.php",
Async:false,
success:function (data) {
result = data;
}
});
return result;
}
Ajax here cannot be used asynchronously, otherwise the function returns, and the result is not assigned, and there is an error. So I added a async:false. It seems that there is no problem. I call this function to get the data normally.
$ (". Btn1"). Click (function () {
var data = GetData1 ();
alert (data);
});
Next, to add another function, because the AJAX request has a certain time consuming, so I need to send the request before the page has a loading effect, that is, the display of a "loading" gif picture, we must have seen. So my handler function becomes this:
$ (". Btn1"). Click (function () {
$ (". Loadingicon"). Show ();
var data = GetData1 ();
$ (". Loadingicon"). Hide ();
alert (data);
});
Display the loading picture before the request, and hide it when the request is complete. It doesn't seem to be a problem. To see the effect, my p.php code sleep for 3 seconds, as follows:
<?php
Sleep (3);
Echo ("aaaaaa");
?>
But when I ran the problem, I clicked on the button and didn't show the loading picture as expected, and the page didn't respond. Ruled out long found the reason, right here in Async:false.
The browser's render (UI) thread is mutually exclusive with the JS thread, and page rendering is blocked when performing JS time-consuming operations. There is no problem when we execute asynchronous Ajax, but when set to sync request, the other actions (the code behind the AJAX function, and the render thread) will stop. Even if my DOM action statement is in the previous sentence of the request, the synchronization request will "quickly" block the UI thread and give it no time to execute. That's why the code is failing.
settimeout Solve blocking problems
Now that we know where the problem is, we will find a way to do it. In order not to allow synchronous AJAX requests blocking threads, I thought of settimeout, put the requested code into the Sesttimeout, let the browser restart a thread to operate, do not solve the problem? So, my code becomes like this:
$('.btn2').click(function(){
$('.loadingicon').show();
setTimeout(function(){
$.ajax({
url : 'p.php',
async : false,
success: function(data){
$('.loadingicon').hide();
alert(data);
}
});
}, 0);
});
SetTimeout's second parameter is set to 0, and the browser executes after a minimum time that has been set. No matter 3,721 run up first to see.
As a result, loading pictures show up, but!!! The picture is not moving, I am clearly a dynamic gif. This time I quickly thought that although the synchronization request was deferred, it would block the UI thread during execution. This block is pretty good, even the GIF picture is not moving, looks like a static picture.
The conclusion is obvious, settimeout palliative, the equivalent of the synchronous request "slightly" asynchronous a bit, next or will go into sync nightmare, blocking threads. Scenario failed.
It's time to use deferred.
After the 1.5 version, jquery introduced the deferred object to provide a convenient generalized asynchronous mechanism. Please refer to Nanyi's article http://www.ruanyifeng.com/blog/2011/08/a_detailed_explanation_of_jquery_deferred_object.html.
So I rewrote the code with the deferred object, as follows:
function getData3(){
var defer = $.Deferred();
$.ajax({
url : 'p.php',
//async : false,
success: function(data){
defer.resolve(data)
}
});
return defer.promise();
}
$('.btn3').click(function(){
$('.loadingicon').show();
$.when(getData3()).done(function(data){
$('.loadingicon').hide();
alert(data);
});
});
You can see that I removed the async:false from the AJAX request, that is, the request was asynchronous. Also note that this sentence in the Success function: Defer.resolve (data), the Resolve method of the deferred object can pass in one parameter, any type. This parameter can be obtained in the Done method, so the data we request asynchronously can be returned in this way.
So far, the problem has been solved. The deferred object is so powerful and convenient that we can make good use of it.
All my test code is as follows, interested students can take to test:
<button class="btn1">async:false</button>
<button class="btn2">setTimeout</button>
<button class="btn3">deferred</button>
<img class="loadingicon" style="position:fixed;left:50%;top:50%;margin-left:-16px;margin-top:-16px;display:none;" src="loading2.gif" Alt="Loading" />
<script>
Function getData1(){
Var result;
$.ajax({
Url : 'p.php',
Async : false,
Success: function(data){
Result = data;
}
});
Return result;
}
$('.btn1').click(function(){
$('.loadingicon').show();
Var data = getData1();
$('.loadingicon').hide();
Alert(data);
});
$('.btn2').click(function(){
$('.loadingicon').show();
setTimeout(function(){
$.ajax({
Url : 'p.php',
Async : false,
Success: function(data){
$('.loadingicon').hide();
Alert(data);
}
});
}, 0);
});
Function getData3(){
Var defer = $.Deferred();
$.ajax({
Url : 'p.php',
//async : false,
Success: function(data){
Defer.resolve(data)
}
});
Return defer.promise();
}
$('.btn3').click(function(){
$('.loadingicon').show();
$.when(getData3()).done(function(data){
$('.loadingicon').hide();
Alert(data);
});
});</script>
Ps:firefox have to do optimization?
The above issues are consistent with the test results in Chrome and IE9. But when I was testing in Firefox, synchronized Ajax did not block the UI thread, which meant that the problem did not exist at all. I did a test with other code, in Firefox, JS thread is really blocking the UI thread, this is no doubt. One possible guess is that Firefox is optimized for synchronized Ajax, and I don't know what the truth is. Have a high man know also please advise.