js样式会影响ajax,js ajax同步请求造成浏览器假死的问题

今天写了一个简单的loading效果,希望在点击加载按钮后会出现loading字样,然后执行ajax同步请求,加载完之后loading样式消失,本来是很简单的需求,结果遇上了很尴尬的问题~

问题:当我点击按钮后,loading字样并没有出现,反而是先执行了ajax请求,请求完成后才出现了loading的样式~

原因:经过各种排查,咨询各方大神,发现原来问题是在于ajax同步请求。浏览器的渲染(UI)线程和js线程是互斥的,在执行js耗时操作时,页面渲染会被阻塞掉。当我们执行异步ajax的时候没有问题,但当设置为同步请求时,其他的动作(ajax函数后面的代码,还有渲染线程)都会停止下来。即使我的DOM操作语句是在发起请求的前一句,这个同步请求也会“迅速”将UI线程阻塞,不给它执行的时间。

解决方式:

1.在ajax外加上setTimeout,让浏览器重启一个线程来操作。

到这里问题就解决了,但是你可以试试当你点击按钮的时候如果需要弹出一个gif图片,并且图片一直在旋转,提示更新中,你会发现图片虽然会显示,但是图片却是不动的,那是因为虽然同步请求延迟执行了,但是它执行期间还是会把UI线程给阻塞。这个阻塞相当牛逼,连gif图片都不动了,看起来像一张静态图片一样。结论很明显,setTimeout治标不治本,相当于把同步请求“稍稍”异步了一下,接下来还是会进入同步的噩梦,阻塞线程,这种方法只适合发请求之前操作简单的时间短的情况。

2.使用 Deferred来解决(可解决gif动画不动的问题)

$('btn').click(function(){

$('.loading').fadeIn();

$.when(getData()).done(function(data){

$('div').html(data);

});

$('.loading').fadeOut();

});

function getData(){

var defer = $.Deferred();

$.ajax({

url:"xxxx.xxx",

type:"post",

data:{},

async:true,//异步

success:function(data){

defer.resolve(data);

}

});

return defer.promise();

}

这里首先创建一个deffered对象,在ajax的success函数中将ajax返回的数据保存在deffered对象中,然后返回deffered对象。这样就保证了在下一次ajax请求的时候这个ajax已经请求完成。deferred对象的好处包括它允许你给一个事件自由添加多个回调函数。或者给多个事件统一指定回调函数。

//===============此处为分割线===============

感谢大神补充,浏览器假死问题主要是js的耗时操作,导致浏览器还没来得及渲染就已经卡住了,简单举例:

$('#btn1').click(function(){

$('.loading-wrap').fadeIn();

for(var i = 0; i < 1000000; i++){

console.log('假死');

}

$('.loading-wrap').fadeOut();

});

这段按钮点击事件,同样会导致浏览器卡死,这与ajax同步请求原理造成的问题相同

你可能感兴趣的:(js样式会影响ajax)