大家好,欢迎来到IT知识分享网。
功能需求
编写点击按钮,弹出loading遮罩层提示正在加载中…,同时查询后台信息,拼接数据后渲染到列表时,为了保障渲染时,列表中的数据已经拼接完成。所以在for循环中使用同步ajax进行请求,在success方法中进行拼接。
function showPrintJobList(){
var loadingTip = $('#loading');
loadingTip.show();
for(var i = 0;i < rwid.length;i++){
$.ajax({
url: xxxxx,
async: false, //默认异步,为保证数据完整和顺序使用同步请求
type: 'POST',
data:{
xxx: xxx
},
dataType: 'json',
success: function(result) {
//.....循环拼接结果,弹窗显示列表:$('#rwlist').show();
},
error: function(err){
console.log(err);
}
});
}
loadingTip.hide();
$('#rwlist').show();
}
IT知识分享网
问题信息
点击按钮后,遮罩层没有弹出,而是等待表单渲染完成后,看到一闪而过的遮罩层。
问题原因async: false
ajax同步请求在运行的时候,浏览器的UI、Dom元素渲染会被阻塞。所以当点击事件触发showPrintJobList函数时,loading.show()是有被加载到浏览器的js运行线程中,但是运行到ajax同步请求时,会将loading.show()阻塞执行,等到同步ajax请求完了,才会运行。然后同步ajax已经请求完了,然后直接被隐藏,然后显示列表。所以会看到一闪而过的loading遮罩层
解决方法
一、使用async wait关键字
二、使用JQuery的Deferred对象和$.when().done().fail()
async/await关键字
- 标识所修饰的函数存在异步代码,函数内部可用await关键字修饰异步过程变为同步。函数内部也可以全部为同步代码。
- 非阻塞:async所标识的函数内存在异步代码,会等待异步代码执行完,但是async函数本身会马上返回,不会阻塞当前js工作主线程,可以简单认为,async函数工作在主线程,同步执行,不会阻塞界面渲染,async函数内部由await关键字修饰的异步过程,工作在相应的协程上,会阻塞等待异步任务的完成再返回;
代码修改如下:
IT知识分享网async function showPrintJobList(){
var loadingTip = $('#loading');
loadingTip.show();
for(var i = 0;i < rwid.length;i++){
await $.ajax({
//使用await关键字修饰异步请求,保证数据顺序完整
url: xxxxx,
async: true, //有await关键字,ajax请求修改为异步
type: 'POST',
data:{
xxx: xxx
},
dataType: 'json',
success: function(result) {
//.....循环拼接结果,弹窗显示列表:$('#rwlist').show();
},
error: function(err){
console.log(err);
}
});
}
loadingTip.hide();
$('#rwlist').show();
}
或者使用JQuery的Deferred对象和$.when().done().fail()使异步请求同步执行,同时不阻塞主线程。
var dataList = [];
function showPrintJobList(){
var defer = $.Deferred();
for(var i = 0;i < rwid.length;i++){
$.ajax({
url: xxxxx,
async: true, //使用Deferred对象,ajax请求修改为异步
type: 'POST',
data:{
xxx: xxx
},
dataType: 'json',
success: function(result) {
//dataList保存结果
dataList.push(result);
defer.resolve(dataList);
},
error: function(err){
defer.reject(err);
}
});
}
return defer;
}
$('button#showList').click(function(){
var loadingTip = $('#loading');
loadingTip.show();
$.when(showPrintJobList()).done(function(data){
//循环拼接data中的list中的数据
loadingTip.hide();
$('#rwlist').show();
}).fail(function(){
console.log(err);
});
}
原理解析
浏览器中一般会运行UI线程、JS线程以及事件触发线程。
在上述上述代码中,loading.show()方法涉及到dom树的更新,所以被加载到了UI线程执行任务中。但是后面的ajax同步请求,因为不是异步的所以浏览器不会重新新增一个线程进行请求,而是直接放在js线程中阻塞其他线程执行。所以UI线程不能执行loading.show()方法。
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/6924.html