一个很常见的需求,前台页面提供一个查询按钮,点击查询后会发出ajax请求后台查询数据,在查询数据的这段时间内,需要为整个页面加上一个遮罩,或者是把查询按钮设定为disable的,以免重复提交查询请求。
首先,想到的方式就是类似如下代码的实现方案:
function doSearch() {
// 将查询按钮置为不可用
$("#searchButton").val("查询中....").attr("disabled", "disabled");
// 发送ajax到后台请求数据,假定后台会在5秒后返回数据
$.ajax({
method:"post",
async:false, // 注意这里的同步(async为是否异步,当这个值为false则是同步ajax请求,为true或不写这个属性则是异步ajax请求)
url:"查询URL路径",
data:"所需参数",
success:function(data) {
// 成功的回调函数
....
},
error:function (data) {
// 失败的回调函数
....
}
});
// 将查询按钮置为可用
$("#searchButton").val("点我查询").attr("disabled", "");
}
这个时候我们预料中的效果是,点击查询按钮后:
查询按钮的文字变为“查询中....”且不可用 -》 ajax发出请求,5秒后后台返回数据 -》 查询按钮文字变为“点我查询”且变为可用状态
然而,事实上的效果是,点击查询按钮后:
ajax发出请求,5秒后后台返回数据 -》查询按钮的文字变为“查询中....”且不可用 -》查询按钮文字变为“点我查询”且变为可用状态
且按钮的文字改变和可用状态的改变是一瞬间的,很难观察到,不过确实是一瞬间完成的,也就是说,在ajax访问后台获取数据的这段时间内,查询按钮并没有任何变化,还是可以点击的,这就很蛋疼了。
解决方案就是:
第一步: 将ajax的同步改为异步,也就是改变ajax中async属性为true或是不写这个属性。
第二步:将按钮样式还原回去的语句放在ajax的success和error回调函数中。
function doSearch() {
// 将查询按钮置为不可用
$("#searchButton").val("查询中....").attr("disabled", "disabled");
// 发送ajax到后台请求数据,假定后台会在5秒后返回数据
$.ajax({
method:"post",
async:true, // 将ajax修改为异步请求,而不再发送同步请求
url:"查询URL路径",
data:"所需参数",
success:function(data) {
// 成功的回调函数
....
// 将查询按钮置为可用
$("#searchButton").val("点我查询").attr("disabled", "");
},
error:function (data) {
// 失败的回调函数
....
// 将查询按钮置为可用
$("#searchButton").val("点我查询").attr("disabled", "");
}
});
}
原因是:
浏览器中有两个引擎,一个是js引擎(这个引擎是用来执行js代码的),一个是渲染(UI)引擎(这个渲染引擎就是用来改变样式的),当我们执行一个function时,首先渲染引擎进行渲染,但是还没渲染完毕,js引擎就执行到了同步ajax,此时js引擎和渲染引擎会互斥,渲染引擎就被js引擎阻塞掉了,当ajax完成执行后,js引擎和渲染引擎的互斥结束。因为ajax已经执行完毕了,所以就没有同步ajax的5秒阻塞效果,从而渲染引擎就会在一瞬间完成“查询按钮的文字变为“查询中....”且不可用 ”到“查询按钮文字变为“点我查询”且变为可用状态”的转换。
当ajax由同步改为异步后,js引擎和渲染引擎不会因为ajax的同步而互斥,所以渲染引擎第一时间就可以渲染出样式效果,需要注意的是,将按钮样式还原回去的语句需要放在ajax的success和error回调函数中,而不是放在function最后,不然这个样式改变效果也是一瞬间就结束了。