You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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)
    })
  }
})()
修复说明
  1. 抽离了独立的进度更新逻辑,每帧仅读取一次最新的处理进度、更新一次DOM,不会出现同帧多次修改被合并的问题,进度更新会完全贴合帧率自然滚动
  2. 把原来一次性执行的3600次同步循环拆分为分块执行,每帧处理一部分任务,不会长时间阻塞渲染线程,保证UI可以正常响应更新
  3. 移除了未定义变量promises相关的错误代码

内容的提问来源于stack exchange,提问作者user2272048

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 10:24:09