在使用jQuery处理AJAX请求时,部分场景为了保证请求完成后再执行后续逻辑,会将async参数设置为false,让请求以同步方式执行。但不少开发者会遇到一个典型问题:提前设置的加载动画完全不会显示,请求完成之后直接跳到了后续逻辑,用户体验受到明显影响。

问题产生原因
浏览器的渲染进程和JavaScript执行进程是共享主线程的。当设置async: false时,AJAX请求会进入同步阻塞模式,主线程会被当前请求完全占用,直到请求返回结果之后才会释放。
而加载动画的显示通常依赖两个步骤:首先是修改DOM元素的状态(比如把隐藏的加载层设为显示),其次是浏览器执行渲染流程把这个变化更新到页面上。当async: false时,修改DOM的操作完成后,主线程立刻被同步请求阻塞,浏览器没有机会执行渲染,自然就看不到加载动画,直到请求结束,主线程空闲后才会一次性渲染所有变化,但此时加载动画往往已经被隐藏了。
常见错误示例
以下是一个典型的出现问题的代码:
// 点击按钮触发请求
$("#btn").click(function() {
// 显示加载动画
$("#loading").show();
// 发起同步AJAX请求
$.ajax({
url: "ipipp.com/api/getData",
type: "get",
async: false,
success: function(res) {
console.log("请求成功", res);
},
error: function(err) {
console.log("请求失败", err);
}
});
// 隐藏加载动画
$("#loading").hide();
});
这段代码中,show()方法只是修改了DOM的显示属性,还没等浏览器渲染,同步请求就阻塞了主线程,所以用户看不到加载动画,请求完成后直接执行hide(),动画始终不会出现在页面上。
解决方案
方案一:改用异步请求,用回调处理后续逻辑
如果业务没有强制要求同步执行,最推荐的方式是把async设为true(默认值),把后续需要依赖请求结果的逻辑放到success回调中,这样主线程不会被阻塞,加载动画可以正常渲染。
$("#btn").click(function() {
// 显示加载动画
$("#loading").show();
// 发起异步AJAX请求
$.ajax({
url: "ipipp.com/api/getData",
type: "get",
async: true,
success: function(res) {
console.log("请求成功", res);
// 后续依赖请求结果的逻辑写在这里
handleData(res);
// 请求完成后隐藏加载动画
$("#loading").hide();
},
error: function(err) {
console.log("请求失败", err);
$("#loading").hide();
}
});
});
function handleData(data) {
// 处理请求返回的数据
console.log("处理数据", data);
}
方案二:拆分同步逻辑,用setTimeout释放主线程
如果必须使用同步请求,可以在显示加载动画之后,用setTimeout把同步请求放到下一个事件循环执行,这样浏览器就有机会先完成渲染。
$("#btn").click(function() {
// 显示加载动画
$("#loading").show();
// 用setTimeout把同步请求放到下一个事件循环,让浏览器先渲染动画
setTimeout(function() {
$.ajax({
url: "ipipp.com/api/getData",
type: "get",
async: false,
success: function(res) {
console.log("请求成功", res);
},
error: function(err) {
console.log("请求失败", err);
}
});
// 请求完成后隐藏加载动画
$("#loading").hide();
}, 0);
});
这种方式利用了JavaScript的事件循环机制,setTimeout的回调会在当前执行栈清空后执行,此时浏览器已经完成了加载动画的渲染,同步请求阻塞主线程时动画已经显示在页面上。
方案三:使用Promise封装异步逻辑
如果后续逻辑依赖多个请求的结果,可以用Promise把AJAX请求封装成异步操作,用then或者async/await处理顺序,既避免同步阻塞,又能保证逻辑的执行顺序。
// 封装AJAX为Promise
function requestData() {
return new Promise(function(resolve, reject) {
$.ajax({
url: "ipipp.com/api/getData",
type: "get",
success: function(res) {
resolve(res);
},
error: function(err) {
reject(err);
}
});
});
}
// 使用async/await处理
$("#btn").click(async function() {
$("#loading").show();
try {
let res = await requestData();
console.log("请求成功", res);
handleData(res);
} catch (err) {
console.log("请求失败", err);
} finally {
// 无论请求成功失败都隐藏加载动画
$("#loading").hide();
}
});
注意事项
首先,现代浏览器已经逐渐废弃了同步AJAX的支持,在主线程中使用async: false可能会在控制台抛出警告,甚至未来会被完全禁用,所以优先选择异步方案是更稳妥的做法。
其次,使用setTimeout的方案虽然能临时解决问题,但同步请求依然会阻塞后续的用户交互,比如用户点击其他按钮、滚动页面等操作都会卡顿,所以只适合临时兼容旧逻辑的场景。
最后,加载动画的显示和隐藏最好统一放在请求的开始和结束位置,避免遗漏隐藏逻辑导致动画一直显示的问题。
jQueryAJAXasync_false加载动画修改时间:2026-07-02 17:42:33