点击按钮后弹窗无法立即关闭:同步XMLHttpRequest阻塞问题
弹窗关闭与同步请求冲突问题解答
问题原因
弹窗不能立即关闭,完全是同步XMLHttpRequest导致的,和EventListener无关。
同步请求会彻底阻塞浏览器的主线程——包括UI渲染。你调用feedbackPopup()后,虽然修改了弹窗的visibility样式,但主线程马上被同步XHR占用,没法立即执行UI更新,必须等请求返回后才会渲染弹窗关闭的状态,所以看起来弹窗要等接口返回才关闭。
至于你说异步时if(xmlHttp.status === 200)代码块不执行,是因为异步请求不会阻塞代码执行,原来的写法没有监听请求完成的事件,代码会直接跳过判断逻辑,自然不会给SomeGlobal赋值。
解决方案
要实现弹窗即时关闭,同时保证SomeGlobal能被正确设置并用于后续逻辑,必须改成异步请求,把依赖全局变量的逻辑放到请求成功的回调里:
修改后的代码示例
- 重构
updateFeedback为异步,并支持回调:
function updateFeedback(a, b, c, callback){ const host = window.location.host; // 注意模板字符串要用反引号,原单引号无法解析变量 let URL = `someURL${a}${b}${c}`; var xmlHttp = new XMLHttpRequest(); xmlHttp.open("GET", URL, true); // 保持异步 // 监听请求完成事件 xmlHttp.onload = function() { if (xmlHttp.status === 200) { SomeGlobal = b; // 请求成功后执行依赖SomeGlobal的后续逻辑 if (typeof callback === 'function') { callback(); } } else { console.log("xmlHttp.status", xmlHttp.status); } }; xmlHttp.send(null); }
- 调整
closeFeedback的执行顺序:
function closeFeedback(){ // 先执行弹窗关闭,主线程不阻塞,UI立即更新 feedbackPopup(); // 调用异步请求,把后续逻辑传入回调 updateFeedback(a, b, c, function() { // 这里写所有依赖SomeGlobal的代码 ... }); }
额外提示
- 同步XHR在现代浏览器中属于不推荐的写法,会导致页面卡顿、无响应,尽量避免使用
- 模板字符串必须用反引号
`包裹,否则${变量}不会被解析成实际值
内容的提问来源于stack exchange,提问作者JoeXYZ
相关产品推荐
相关产品推荐

