如何在网站计算任务执行期间显示加载动画并在完成后隐藏
问题场景
正在开发支持数值计算、图表绘制功能的网站,需要实现计算运行阶段展示加载动画、计算和绘图全部完成后动画自动消失的交互效果。
补充说明:该效果和页面初始加载流程无关,常规的页面初始化加载器方案不适用。
现有实现逻辑
- 点击id为
submitButton的触发按钮时,将承载加载动画、id为loader的div容器的display样式设置为flex,尝试显示加载动画 - 后续待执行逻辑:生成指定长度的随机数组、执行
permutationGeneration排列生成函数、统计计算耗时、完成最终图表绘制 - 当前卡点:仅实现了加载动画的触发显示逻辑,无法在计算执行完毕、图表绘制结束后,将
loader的display样式改回none以隐藏动画
现有代码片段如下:
document.getElementById("submitButton").onclick=function() { document.getElementById("loader").style.display='flex'; // 加载动画容器 const permutationGeneration = (arr = []) => { let res = [] const helper = (arr2) => { if (arr2.length==arr.length) return res.push(arr2) for(let e of arr) if (!arr2.includes(e)) helper([...arr2, e]) }; helper([]) delete result; return; }; var randArray=Array.from({length : size}, () => Math.floor(Math.random() * 100000)); timeReq = new Date().getTime(); permutationGeneration(randArray); timeReq = ((new Date().getTime()) - timeReq)/1000; }
问题根因
浏览器JS运行在单线程事件循环模型下:如果在设置loader.style.display='flex'后直接执行同步的耗时计算逻辑,浏览器会被计算任务占满线程,没有空闲执行页面重渲染,用户根本看不到加载动画;就算在计算代码最后直接加隐藏逻辑,也会出现动画全程不显示、或者闪一下就消失的问题。
另外原代码的permutationGeneration函数存在逻辑错误:内部生成的排列结果res没有对外返回,末尾的delete result是无效代码,不会产生实际作用。
修复方案
- 用
setTimeout(fn, 0)将计算、绘图逻辑包裹,推入下一个宏任务队列,给浏览器留出重渲染时间,确保加载动画能正常显示 - 在所有计算、绘图逻辑全部执行完成的位置,添加隐藏loader的代码
- 修正原排列生成函数的返回逻辑
修正后可直接运行的代码如下:
document.getElementById("submitButton").onclick = function() { const loaderEl = document.getElementById("loader"); // 触发展示加载动画 loaderEl.style.display = 'flex'; const permutationGeneration = (arr = []) => { let res = [] const helper = (arr2) => { if (arr2.length == arr.length) { res.push(arr2) return } for(let e of arr) { if (!arr2.includes(e)) { helper([...arr2, e]) } } }; helper([]) // 移除无效的delete逻辑,返回生成的排列结果 return res; }; // 将耗时逻辑放入setTimeout,等浏览器渲染完加载动画后再执行 setTimeout(() => { const randArray = Array.from({length : size}, () => Math.floor(Math.random() * 100000)); const timeStart = new Date().getTime(); const generateResult = permutationGeneration(randArray); const timeReq = ((new Date().getTime()) - timeStart)/1000; // 此处插入你的图表绘制逻辑 // ...... 图表绘制代码 ...... // 如果绘图逻辑是异步的(比如第三方图表库的渲染回调),需要把隐藏loader的代码放到对应的完成回调中 // 全部逻辑执行完毕,隐藏加载动画 loaderEl.style.display = 'none'; }, 0) }
注意事项
- 如果使用的图表库存在异步渲染逻辑,不要直接在调用绘图接口后就隐藏loader,需要把隐藏逻辑放到图表库提供的
rendered/finished类回调函数中,避免图表还没绘制完成动画就提前消失 - 如果计算量特别大,更推荐将计算逻辑放到
Web Worker中执行,避免阻塞主线程导致加载动画卡顿
内容的提问来源于stack exchange,提问作者Chandranshu Gautam
相关产品推荐
相关产品推荐

