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

如何实现循环计数器与顺序执行的双倒计时定时器

解决顺序定时器与循环次数显示问题

核心问题分析

原代码的问题在于:

  • for 循环是同步执行的,瞬间完成所有迭代,直接把循环次数设为最终值,同时启动所有定时器,导致所有倒计时同时运行
  • RunTimer 是无阻塞的异步函数,无法直接控制执行顺序

解决方案代码

修改后的完整可运行代码如下:

<!doctype html>
<html lang="en">
  <head>
    <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

    <!-- Bootstrap CSS -->
    <link rel="stylesheet" href="/static/css/bootstrap.min.css">

    <title> Timer Scherm </title>
  </head>
  <body>
    <div class="container">
        
        
    <h1> Timer Scherm </h1>
    </br>

    <div class="row mb-3 text-left">
      <div class="col-6 col-sm-1 themed-grid-col"><h5>Step: 3</h5></div>
      <div class="col-6 col-sm-4 themed-grid-col"><h5>Fase: 15m 3 Sets Rapid</h5></div>
      <div class="col-6 col-sm-2 themed-grid-col"><h5>Edge: 3.0 sec.</h5></div>
      <div class="col-6 col-sm-2 themed-grid-col"><h5>Face: 6.0 sec.</h5></div>
      <div class="col-6 col-sm-2 themed-grid-col"><h5>Reps: 3 times</h5></div>
    </div>

    <h1 class="text-primary">
      <p id="RepeatCounter"></p>
    </h1>

    </br>

    <h1 class="text-danger">
      <div id="countdownEdge"></div>
    </h1>

    </br>

    <h1 class="text-success">
        <div id="countdownFace"></div>
    </h1>

    <script>
      const Repeats = 3;
      const timeleftEdge = 3.0;
      const timeleftFace = 6.0;

      // 启动整个流程
      startTimerSequence();

      // 异步函数,控制整个定时器序列
      async function startTimerSequence() {
        for (let index = 1; index <= Repeats; index++) {
          // 更新当前循环次数
          document.getElementById("RepeatCounter").innerHTML = "Repeat : " + index.toFixed(0) + " time";
          // 先执行Edge定时器,等待它结束
          await RunTimer(timeleftEdge, 'countdownEdge', 'Edge');
          // 再执行Face定时器,等待它结束
          await RunTimer(timeleftFace, 'countdownFace', 'Face');
        }
      }

      // 改造为返回Promise的定时器函数,便于await等待结束
      function RunTimer(totalTime, DIV_ID, Type) {
        return new Promise((resolve) => {
          let timeleft = totalTime; // 用局部变量保存时间,避免闭包问题
          const Timer = setInterval(function(){
            if(timeleft <= 0){
              clearInterval(Timer);
              document.getElementById(DIV_ID).innerHTML = "Ready";
              resolve(); // 定时器结束,resolve Promise
            } else {
              document.getElementById(DIV_ID).innerHTML = Type + " :   " + timeleft.toFixed(1) + " seconds remaining";
            }
            timeleft -= 0.1;
          }, 100);
        });
      }
    </script>



    </div>

    <!-- Optional JavaScript -->
    <!-- jQuery first, then Popper.js, then Bootstrap JS -->
    <script src="/static/js/jquery-3.7.1.slim.min.js"></script>
    <script src="/static/js/popper.min.js"></script>
    <script src="/static/js/bootstrap.min.js"></script>

  </body>
</html>

关键改动说明

  1. RunTimer 改造为Promise函数

    • 用new Promise包裹定时器逻辑,当倒计时结束时调用resolve(),标记该定时器任务完成
    • 将timeleft改为函数内部的局部变量,避免原代码中闭包导致的时间变量共享问题
  2. 异步循环控制

    • 创建startTimerSequence异步函数,结合await确保每次循环中:
      • 先更新当前循环次数
      • 等待Edge定时器完全结束后,再启动Face定时器
      • 两个定时器都结束后,再进入下一次循环
  3. 循环次数正确显示

    • 循环异步执行,每次迭代都会先更新RepeatCounter内容,再执行定时器,因此会逐步显示当前循环次数,而非直接跳到最终值

适配数据库数据的版本

如果要替换为数据库获取的变量,只需修改初始变量:

const Repeats = {{ fase['rep'] }};
const timeleftEdge = {{ fase['edge'] }};
const timeleftFace = {{ fase['face'] }};

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 10:07:03