XMLHttpRequest请求前加载Spinner不显示问题排查
问题:无法显示加载Spinner的原因分析
我使用原生JavaScript类向其他页面发送请求,希望在请求结束前显示加载Spinner。我编写的代码会在创建XMLHttpRequest实例前调用加载Spinner,请求结束后移除它,但代码无报错却无法在浏览器中看到加载Spinner,请问我遗漏了什么?
class BYEPC_HTTPRequest { constructor(uri, params) { this.uri = uri; this.params = params; this.response; this.loadingSpinner(); // I added loadingSpinner to document before XMLHttpRequest. this.callQueryPage(); } loadingSpinner() { document.body.insertAdjacentHTML('beforeend', ` <style> .loader { border: 16px solid #f3f3f3; border-radius: 50%; border-top: 16px solid #3498db; animation: spin 2s linear infinite; z-Index: 100000; position: fixed; display: block; boxShadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19); width: 70px; height: 70px; top: 50%; left: 50%; top: 40%; left: 40%; transform: translate(-50%, -50%); msTransform: translate(-50%, -50%); webkitTransform: translate(-50%, -50%); } @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } </style> <div id="loader" class="loader"></div> ` ); } callQueryPage() { var httpRequest = new XMLHttpRequest(); httpRequest.onloadend = function(e) { document.getElementById('loader').remove(); }; let _this = this; httpRequest.onreadystatechange = function(){ if (httpRequest.readyState === XMLHttpRequest.DONE) { if (httpRequest.status === 200) { _this.response = httpRequest.responseText; } else { alert("status : " + httpRequest.status); } } } httpRequest.open("POST", this.uri, false); httpRequest.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); httpRequest.send(this.params); } sleep(delay) { const delayUntil = Date.now() + delay; while(Date.now() < delayUntil); } }
核心问题:同步请求阻塞浏览器渲染
你在httpRequest.open中使用了同步请求(第三个参数为false),这会直接阻塞浏览器主线程:在请求完成前,浏览器没有时间去渲染刚插入的Spinner元素,请求结束后Spinner又被立刻移除,所以完全看不到它的存在。
修复方案
切换为异步请求
将httpRequest.open("POST", this.uri, false);中的false改为true,让请求在后台执行,不占用主线程的渲染资源。修正样式问题(可选)
z-Index写法错误,应改为驼峰式zIndex或带引号的"z-index",否则样式可能不生效;- 重复设置了
top和left,删除冗余的top:40%; left:40%;,保留top:50%; left:50%;配合transform实现居中; - 避免每次实例化类都插入重复的
<style>标签,建议将样式提前放到页面<head>中。
增加元素存在判断
在移除Spinner时加个判断,避免请求异常时找不到元素报错:httpRequest.onloadend = function(e) { const loader = document.getElementById('loader'); if (loader) loader.remove(); };
修复后的callQueryPage方法示例
callQueryPage() { var httpRequest = new XMLHttpRequest(); httpRequest.onloadend = function(e) { const loader = document.getElementById('loader'); if (loader) loader.remove(); }; let _this = this; httpRequest.onreadystatechange = function(){ if (httpRequest.readyState === XMLHttpRequest.DONE) { if (httpRequest.status === 200) { _this.response = httpRequest.responseText; } else { alert("status : " + httpRequest.status); } } } // 改为异步请求 httpRequest.open("POST", this.uri, true); httpRequest.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); httpRequest.send(this.params); }
内容的提问来源于stack exchange,提问作者seongmincho
相关产品推荐
相关产品推荐

