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

如何在长耗时计算循环中让progressBar正常工作?原生JS实现方案

纯JS实现长时间计算场景下的进度条实时更新

核心问题原因

浏览器的JavaScript执行和UI渲染共享主线程,你原代码中的素数生成是同步密集型运算,全程占满主线程资源,浏览器没有空闲时间执行重绘操作,因此进度条会卡住直到计算全部完成才会一次性更新。

方案选择

优先使用async/await方案实现,相比setInterval可控性更高,不会出现回调堆积、进度更新错位的问题。

实现逻辑

  1. 计算过程中定时更新进度条的DOM属性(宽度、百分比文本)
  2. 定期让出主线程给浏览器执行UI渲染,通过await一个0延时的Promise实现线程出让
  3. 调整出让频率平衡性能和流畅度:不需要每次循环都出让,比如每处理1000个数字、或者进度每上涨1%时出让一次即可,避免不必要的性能损耗

完整可运行代码

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <meta http-equiv="X-UA-Compatible" content="ie=edge" />
  <title>素数生成进度条Demo</title>
  <style type="text/css">
    #myProgress {
      width: 100%;
      background-color: #ddd;
    }
    #myBar {
      width: 0%;
      height: 30px;
      background-color: #4caf50;
      text-align: center;
      line-height: 30px;
      color: white;
      transition: width 0.1s linear;
    }
  </style>
</head>
<body>
  <div style="text-align: center">
    <h2>RSA素数生成</h2>
    <div id="myProgress">
      <div id="myBar">0%</div>
    </div>
    <br />
    <label>输入素数的范围,最大:21474836:</label>
    <input
      type="number"
      id="myCount"
      placeholder=""
      value="2147483"
      min="100"
      max="21474836"
    />
    <button class="dom1" onclick="initPrim()">1.素数生成器</button><br />
    <div
      id="result0"
      style="width: 100%; word-break: break-all; word-wrap: break-word"
    ></div>
    <br />
  </div>
</body>
<script>
  var PrimeArray = [2];
  // 线程让出工具函数
  function yieldThread() {
    return new Promise(resolve => setTimeout(resolve, 0));
  }
  //initPrim 生成素数表
  async function initPrim() {
    PrimeArray = [2]; // 重置素数数组,避免多次点击数据累加
    const resultDom = document.getElementById("result0");
    const progressBar = document.getElementById("myBar");
    resultDom.innerHTML = " ";
    const count = Number(document.getElementById("myCount").value);
    // 每1%进度出让一次线程,可根据需求调整频率
    const yieldStep = Math.max(1, Math.floor(count / 100));
    for (let i = 2; i < count; i++) {
      let tag = 0;
      const sqrtI = Math.sqrt(i) + 1;
      for (let j = 0; j < PrimeArray.length && PrimeArray[j] < sqrtI; j++) {
        if (i % PrimeArray[j] == 0) {
          tag = 1;
          break;
        }
      }
      if (tag == 0) {
        PrimeArray.push(i);
      }
      // 达到出让阈值时更新进度并让出线程
      if (i % yieldStep === 0) {
        const progress = Math.floor((i / count) * 100);
        progressBar.style.width = `${progress}%`;
        progressBar.innerText = `${progress}%`;
        await yieldThread();
      }
    }
    // 计算完成后设置进度为100%
    progressBar.style.width = "100%";
    progressBar.innerText = "100%";
    resultDom.append("p=\t" + PrimeArray);
  }
</script>
</html>

优化点说明

  • 提前计算Math.sqrt(i)避免重复运算,提升计算性能
  • 增加了进度条的过渡动画,视觉更流畅
  • 支持多次点击生成,每次自动重置素数数组和进度条
  • 动态计算出让阈值,不管输入的数值大小,都只会让出100次左右线程,平衡性能和更新频率

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 12:27:09