You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何避免JavaScript中setInterval执行两次导致重复输出?

解决setInterval重复执行导致内容重复的问题

你遇到的核心问题是定时器被重复注册了——每次通过$('.image-area').load()加载页面内容时,返回的HTML里包含的<script>代码会重新执行一遍,创建一个新的setInterval定时器。时间一长就会有多个定时器同时工作,每2秒触发多次更新,自然就导致内容重复了。

下面给你几个可行的解决方案:

方案1:将脚本移到base.html,确保只执行一次

把dashboard.html里的JavaScript代码移到base.html的<body>末尾(确保在页面元素加载完成后执行),这样不管怎么调用load()更新内容,脚本只会初始化一次定时器,从根源避免重复。

修改后的base.html末尾可以这样添加代码:

<script type="text/javascript">
  let updateTimer = null;
  let first_time = 0;
  let current_count = 0;
  let total_count = 0;

  function update(){
    if (first_time == 0){
      current_count = $('td').length;
      total_count = current_count;
      first_time = 1;
      $('body').append("<p class='notify'>No new images</p>");
    } else {
      total_count = $('td').length;
      if (total_count > current_count){
        $('.notify').text(total_count - current_count + " images added !");
        $('html, body').animate({scrollTop:$(document).height()}, 'slow');
        current_count = total_count;
      }
    }
  }

  // 确保只创建一个定时器
  if (!updateTimer) {
    updateTimer = setInterval(function(){
      $('.image-area').load("{{ url_for('image', im=image_date) }}", function() {
        // 把update()放到load的回调里,确保DOM更新后再执行统计
        update();
      });
    }, 2000);
  }

  // 页面卸载时清除定时器,避免内存泄漏
  $(window).on('beforeunload', function() {
    if (updateTimer) clearInterval(updateTimer);
  });
</script>

同时记得删除dashboard.html里的<script>代码块,避免重复加载执行。

方案2:每次更新前清除旧定时器(不移动脚本的情况)

如果不想调整脚本位置,也可以在创建新定时器前清除旧的,或者改用setTimeout实现循环更新(更稳妥,能避免定时器重叠):

修改dashboard.html里的脚本:

let updateTimer = null;
let first_time = 0;
let current_count = 0;
let total_count = 0;

function update(){
  if (first_time == 0){
    current_count = $('td').length;
    total_count = current_count;
    first_time = 1;
    $('body').append("<p class='notify'>No new images</p>");
  } else {
    total_count = $('td').length;
    if (total_count > current_count){
      $('.notify').text(total_count - current_count + " images added !");
      $('html, body').animate({scrollTop:$(document).height()}, 'slow');
      current_count = total_count;
    }
  }
}

function updateCycle() {
  $('.image-area').load("{{ url_for('image', im=image_date) }}", function() {
    update();
    // 完成一次更新后,再设置下一次定时器
    updateTimer = setTimeout(updateCycle, 2000);
  });
}

// 页面加载时启动循环
updateCycle();

// 页面卸载时清除定时器
$(window).on('beforeunload', function() {
  if (updateTimer) clearTimeout(updateTimer);
});

额外注意点

  • 原来的代码中update()load()是并行执行的,可能DOM还没更新完就开始统计了,导致计数不准确。把update()放到load()的回调函数里,能确保页面内容更新后再执行统计逻辑。
  • 尽量避免把变量挂载到window对象上,用局部变量更安全,也不会污染全局作用域。

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

火山引擎 最新活动