项目进行中遇到了同步ajax阻塞ui线程阻塞的问题,原因是执行两个同步ajax请求为一次完整的方法,因业务需求需要循环执行这个方法,检查后台返回的数据正确,但是由于ajax请求时间过长,考虑增加遮罩层与loading图标,
这时遇到该问题,loading图标 .后面的出图也是所有方法执行后只出一个图
代码类似于这样:
$(function(){ for(var key in data){//循环执行 $('#mask').css('display','block');//遮罩层 doAjax(); $('#mask').css('display','none');//去除遮罩层 } }); var doAjax = { aAjax:function(){//第一个ajax请求 ajax({ async:false url:url, success:function(){ doAjax.bAjax(); } }); }; bAjax : function(){//第二个ajax请求 ajax({ async:false url:url, success:function(){ doAjax.doHightCharts(); } }); }; doHighCharts:function(){ //出图 } }
此时为每一个过程考虑两次js阻碍ui线程的加载,第一次添加遮罩层时,第二次为加载highcharts出图时.
考虑两次的原因均因为async:false的原因.由于浏览器的渲染(UI)与与js线程是互斥的,在执行js耗时操作时,页面渲染会被阻塞掉。当我们执行异步ajax的时候没有问题,但当设置为同步请求时,其他的动作(ajax函数后面的代码,还有渲染线程)都会停止下来。即使我的DOM操作语句是在发起请求的前一句($('#mask').css('display','block');//遮罩层),这个同步请求也会“迅速”将UI线程阻塞,不给它执行的时间。这就是代码失效的原因。
在探究这个问题时,了解到更多的知识:(由于项目工期紧,没能使用各种方法实现)
项目中的这个难题使用最简单易懂的方式:
setTimeout解决阻塞问题:
var flag = { num:0 } $(function(){ $('#mask').css('display','block');//遮罩层 setTimeout{//首先执行一次 doAjax(),0 } }); var doAjax = { aAjax:function(){//第一个ajax请求 ajax({ async:true,//可以异步 url:url, success:function(){ doAjax.bAjax(); } }); }; bAjax : function(){//第二个ajax请求 ajax({ async:true,//可以异步 url:url, success:function(){ flag.num++;//此时执行避免异步 if (flag.num < data.length) { setTimeout(doAjax.aAjax(), 100); } doAjax.doHightCharts(); if(flag.num==data.length){ $('#mask').css('display','none');//去除遮罩层 } } }); }; doHighCharts:function(){ //出图 } }
此时简单来说,setTimeout将方法排列的js执行队列的最后(哪怕设置第二个参数为0),所以说使用setTimeout是为了确保UI刷新线程不被阻塞.
理解此过程可以根据:
在这里进行简单的总结:
1.