同步 ajax 会直接阻塞 dom 渲染,导致 ui 线程无法重绘,即使先调用 $('#loading').show() 也无效;修复必须移除 async: false,改用 promise 或 async/await,并注意后端 session 锁可能加剧阻塞。

同步 AJAX 会直接阻塞 DOM 渲染,不是“延迟执行”,而是“不给机会执行”
只要 async: false 出现在 $.ajax 配置里,浏览器主线程就立刻被锁死。哪怕你先调用 $('#loading').show(),再发同步请求,DOM 状态确实改了,但 UI 线程根本没机会重绘——它被 JS 线程占着,连 GIF 动画都会停转,看起来像一张静态图。
这不是浏览器 bug,是单线程模型的必然行为。Chrome、Firefox、Edge、IE8+ 全部如此,没有例外。
- DOM 操作(如
.show()、.addClass())只是修改内存中的节点状态,不等于画面更新 - 画面更新依赖浏览器在 JS 执行间隙主动触发重排(reflow)和重绘(repaint)
-
async: false让 JS 线程持续占用,直到请求完成,UI 线程全程被饿死
排查时重点检查这三类代码模式
很多团队误以为“只要 loading 代码写在 ajax 前面就一定生效”,其实很容易漏掉隐蔽的同步调用链。
- 显式使用
async: false的$.ajax调用(包括封装过的工具函数) - jQuery 旧版本中未显式声明
async,但被全局覆盖为false(例如通过$.ajaxSetup({ async: false })) - 调用了内部含同步 XHR 的第三方库或原生
XMLHttpRequest实例(比如某些老版 SDK、统计埋点脚本)
建议全局搜索:async.*false、XMLHttpRequest.*open.*false、ajaxSetup,不要只盯住单个函数。
使用 PptxGenJS 和 Python 解析,将结构化的 HTML/CSS 幻灯片内容转换为原生、可编辑的 PowerPoint(.pptx)演示文稿。
修复必须移除 async: false,不能靠 setTimeout “骗过”主线程
setTimeout(fn, 0) 把同步请求包一层,看似“异步”,实际只是把阻塞推迟到下一个宏任务开始——UI 依然卡死,loading 还是不显示,GIF 依旧静止。这是典型治标不治本。
- 真正有效的替代方案只有两类:Promise 链(
fetch或$.ajax+.then())或async/await - 若需保证多个请求顺序执行,用
await串行,而非退回同步模式 - jQuery 用户可直接用
$.when(...).done()聚合多个异步请求,避免嵌套回调
示例(安全替换):
async function loadData() {
$('#loading').show();
try {
const res = await $.ajax({ url: '/api/data', async: true }); // 必须显式设 true 或删掉
render(res);
} finally {
$('#loading').hide();
}
}
后端 Session 锁可能放大前端阻塞感知
如果多个同步 AJAX 请求指向同一域名下的不同接口,且后端用了 PHP 默认 session 文件锁或 ASP.NET MVC 的读写 Session,默认会串行化处理——前端一个请求卡住,其他请求也排队等锁。这时你会看到“明明是异步请求,却像同步一样慢”。
- 现象:多个按钮点击后 loading 不出现,且所有请求响应时间异常接近(如都卡在 3s 左右)
- 验证方式:用 curl 或 Postman 单独请求各接口,看是否仍慢;或临时关闭后端 Session(如 PHP 中注释
session_start()) - 修复不在前端:PHP 加
session_write_close(),ASP.NET 加[SessionState(SessionStateBehavior.ReadOnly)]
这个点容易被忽略——前端修好了 async: false,但用户仍抱怨“页面卡”,问题其实藏在服务端。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










