HTML中记录Promise循环进度时DOM更新跳步不流畅该如何修复
问题根因
- 你在同步执行的
while循环里一次性注册了3600个requestAnimationFrame回调。浏览器正常渲染帧率为60fps,每16ms左右才会执行一次所有排队的requestAnimationFrame任务,同一帧内对同一个DOM的多次样式、内容修改会被浏览器合并,仅保留最后一次生效结果,所以中间的百分比更新全部被跳过,视觉上就会出现进度跳变的情况。 - 代码末尾
await Promise.all(promises)中的promises变量未定义,运行时会直接抛出错误。
修复方案
核心思路是每帧仅更新一次最新进度值,同时避免同步长循环阻塞渲染线程。修复后的代码如下:
;(async () => { const width = document.getElementById('width') const numOfImages = 8 const images = Array.from(Array(numOfImages).keys()) const pixelsPerImage = 3600 const totalPixels = numOfImages * pixelsPerImage // 全局记录已处理的总像素数 let currentProcessed = 0 // 独立的进度更新逻辑,每帧仅执行一次 function updateProgress() { const prcnt = ((100 / totalPixels) * currentProcessed).toFixed(2) width.innerHTML = `${prcnt}%` width.style.width = `${prcnt}%` if (currentProcessed < totalPixels) { window.requestAnimationFrame(updateProgress) } } // 启动进度更新轮询 updateProgress() for (let img of images) { await new Promise((resolve) => { // 此处对应实际的image.onload回调 setTimeout(() => { let i = 0 // 分块处理像素,避免长同步任务阻塞主线程 function processChunk() { // 每帧处理的像素数,可根据实际业务调整 const chunkSize = 100 const end = Math.min(i + chunkSize, pixelsPerImage) while (i < end) { // 此处替换为实际的像素处理逻辑 currentProcessed++ i++ } if (i < pixelsPerImage) { window.requestAnimationFrame(processChunk) } else { resolve() } } processChunk() }, 5000) }) } })()
修复说明
- 抽离了独立的进度更新逻辑,每帧仅读取一次最新的处理进度、更新一次DOM,不会出现同帧多次修改被合并的问题,进度更新会完全贴合帧率自然滚动
- 把原来一次性执行的3600次同步循环拆分为分块执行,每帧处理一部分任务,不会长时间阻塞渲染线程,保证UI可以正常响应更新
- 移除了未定义变量
promises相关的错误代码
内容的提问来源于stack exchange,提问作者user2272048
相关产品推荐
相关产品推荐

