loading效果实现原理
# loading 效果实现原理笔记
## 问题背景
function changeSetting(setting) {console.log(setting);loading.value = true;setShow(false);draw();loading.value = false;}
在 `charts.vue` 文件中,点击高级设置的确定按钮后,设置了 `loading.value = true`,但用户看不到 loading 效果,因为代码立即执行了 `draw()` 并设置 `loading.value = false`。
## 原因分析
1. **JavaScript 单线程执行**:所有代码在一个主线程按顺序执行,同一时间只能做一件事。
2. **渲染与 JS 互斥**:浏览器渲染(更新 DOM、绘制界面)和 JavaScript 执行在同一线程,不能同时进行。
3. **事件循环机制**:如果 `loading.value = true` 和 `loading.value = false` 在同一事件循环中执行,浏览器没有机会渲染中间状态。
4. **执行速度过快**:代码执行速度极快,用户无法感知到短暂的 loading 状态。
## 解决方案
使用 `setTimeout` 延迟执行 `draw()` 和 `loading.value = false`,给浏览器渲染的机会:
function changeSetting(setting) {console.log(setting);loading.value = true;setShow(false);// 使用 setTimeout 确保 loading 有足够时间显示setTimeout(() => {draw();loading.value = false;}, 300);}
## 关键原理
1. **事件循环**:JavaScript 执行和浏览器渲染在不同的阶段进行。
2. **任务队列**:`setTimeout` 将回调函数放入任务队列,延迟执行。
3. **渲染时机**:当前事件循环结束后,浏览器会进行渲染,此时用户能看到 loading 效果。
4. **异步执行**:`setTimeout` 不是让代码变成异步,而是改变了代码的执行时机。
## 总结
- 不延迟时:代码在同一事件循环同步执行,没有渲染机会。
- 延迟后:`loading.value = true` 立即执行,回调函数延迟到下一事件循环,中间浏览器进行渲染。
- 300ms 延迟:给用户足够的视觉感知时间,同时不会让用户等待过久。