Jquery ajax 进行网络请求,同步阻塞引起的UI线程阻塞 (loading图片不显示 )

jax重新获取数据刷新页面功能,因为ajax属于耗时操作,想在获取数据且加载页面时显示加载遮罩层,结果发现了ajax的好多坑。

ajax 执行http网络请示时时,让遮罩层显示,ajax加载完毕后遮罩层消失。

因为我想让loadChart()在赋值操作后执行,但如果async设为true时,往往会先执行loadChart(),之后才会赋值,

所以我只能将ajax设为同步。但同步后无论我怎么点按钮,遮罩层都不会出来。

解决方法 1:

这时:只有:async:true , loading mask层才会出来

原因就是ajax的async设置为true时,ajax会委托浏览器另起一个线程,此线程与js线程和ui线程不冲突,只是在执行完成后再插入js事件环。

而ajax的async设置为false时并没有启动单独的线程,还是在js主线程中执行,所以会与浏览器的渲染(UI)线程和js线程是互斥的,在执行js耗时操作时,页面渲染会被阻塞掉。

当我们执行异步ajax的时候没有问题,但当设置为同步请求时,其他的动作(ajax函数后面的代码,还有渲染线程)都会停止下来。即使我的DOM操作语句是在发起请求的前一句,这个同步请求也会"迅速"将UI线程阻塞,不给它执行的时间。这就是代码失效的原因。

解决方法 2:

那么需要使用到: deferred对象。

总之,想让ajax走完再加载页面,就要使用同步。但是只要同步,ajax就会阻塞ui线程,使得loading显示不出来。

只有使用了deffer对象和.when(),既可以ajax设为异步,保证了loading的正常显示,又可以保证在ajax走完再加载页面。因为.when().done()会在deffer.resolve()之前的代码全部走完后才走done中的代码。

我改成这样。由于ajax为同步时点击切换比较卡。能用异步最好还是用异步,用defferred对象后就可以把async换成true了。$.when()函数只接受defferred对象,所以我们在toGetData中需要先创建对象,再return就解决了。defer.resolve(ret)用于控制ajax何时结束,比如我执行完赋值操作结束ajax,进入.done()中的回调函数,它还可以把数据ret也带出来使用,这里我没有用到,这里执行完loadChart()操作后遮罩层消失。所以它能保证deffer.resolve之前的代码执行完再执行回到函数,async设为true也没任何影响。

这样就完美解决了因为ajax阻塞线程导致loading层出不来的问题啦。

<script>

var data;

function toGetData() {

var defer = $.Deferred();

$.ajax({

url: 'xxx',

type: "post", // 请求类型

data: {

},

dataType: 'json',

async: true, // 是否异步

success: function (ret) {

if (ret) {

data=ret;

defer.resolve(ret)

} else {

alert("无数据");

}

}

});

return defer;

}

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

$(".shadow").show()

$.when(toGetData()).done(function(ret){

loadChart()

$(".shodow").hide() //所有的ajax的逻辑可以在这个地方进行处理

});

})

</script>

什么是deferred对象?

开发网站的过程中,我们经常遇到某些耗时很长的javascript操作。其中,既有异步的操作(比如ajax读取服务器数据),也有同步的操作(比如遍历一个大型数组),它们都不是立即能得到结果的。

通常的做法是,为它们指定回调函数(callback)。即事先规定,一旦它们运行结束,应该调用哪些函数。

但是,在回调函数方面,jQuery的功能非常弱。为了改变这一点,jQuery开发团队就设计了deferred对象

**简单说,deferred对象就是jQuery的回调函数解决方案。**在英语中,defer的意思是"延迟",所以deferred对象的含义就是"延迟"到未来某个点再执行。

它解决了如何处理耗时操作的问题,对那些操作提供了更好的控制,以及统一的编程接口。它的主要功能,可以归结为四点。下面我们通过示例代码,一步步来学习。

$.ajax({

url: "test.html",

success: function(){

alert("哈哈,成功了!");

},

error:function(){

alert("出错啦!");

}

});

ajax操作的链式写法

$.ajax("test.html")

.done(function(){ alert("哈哈,成功了!"); })

.fail(function(){ alert("出错啦!"); });

指定同一操作的多个回调函数

$.ajax("test.html")

.done(function(){ alert("哈哈,成功了!");} )

.fail(function(){ alert("出错啦!"); } )

.done(function(){ alert("第二个回调函数!");} );

多个操作指定回调函数

.when(.ajax("test1.html"), $.ajax("test2.html"))

.done(function(){ alert("哈哈,成功了!"); })

.fail(function(){ alert("出错啦!"); });

普通操作的回调函数接口

var wait = function(){

var tasks = function(){

alert("执行完毕!");

};

setTimeout(tasks,5000);

};

普通回调函数需要改造:

var dtd= $.Deferred(); // 新建一个deferred对象

var wait = function(dtd){

var tasks = function(){

alert("执行完毕!");

dtd.resolve(); // 改变deferred对象的执行状态

};

setTimeout(tasks,5000);

return dtd;

};

$.when(wait())

.done(function(){ alert("哈哈,成功了!"); })

.fail(function(){ alert("出错啦!"); });

上面这种写法,还是有问题。那就是dtd是一个全局对象,所以它的执行状态可以从外部改变。

参考:

jQuery的deferred对象详解 - 阮一峰的网络日志

相关推荐
瑞雨溪26 分钟前
AJAX的基本使用
前端·javascript·ajax
jessezappy2 小时前
jQuery-Word-Export 使用记录及完整修正文件下载 jquery.wordexport.js
前端·word·jquery·filesaver·word-export
初九之潜龙勿用10 小时前
C#校验画布签名图片是否为空白
开发语言·ui·c#·.net
MediaTea10 小时前
七次课掌握 Photoshop:绘画与修饰
ui·photoshop
syj_11115 小时前
初识ArkUI
ui·arkts·arkui
芋芋qwq1 天前
Unity UI射线检测 道具拖拽
ui·unity·游戏引擎
鸿蒙自习室1 天前
鸿蒙多线程开发——线程间数据通信对象02
ui·harmonyos·鸿蒙
大霞上仙1 天前
element ui table 每行不同状态
vue.js·ui·elementui
栈老师不回家1 天前
Element UI 组件库详解【Vue】
前端·vue.js·ui
郭梧悠2 天前
HarmonyOS(57) UI性能优化
ui·性能优化·harmonyos