首页 > 解决方案 > setInterval“跳闸”本身并启动第二个间隔计时器

问题描述

我编写了一个选项卡功能,可以在一段时间后在选项卡之间切换,这似乎工作得很好,但是,它已经引起我的注意,有时它会中断。

在查看setInterval并查看错误本身后,它看起来像setInterval在 20-30 分钟后,自行跳闸并启动第二个计时器。这会导致同时显示 2 个选项卡。

我在网上读过一些内容,基本上它与 Javascript 是单线程的有关,这只是一个基本缺陷setInterval,如果它跳闸,它不会重置计时器,它只会创建第二个计时器。是否有为此行程添加错误捕获或运行重复超时功能的更好方法?

jQuery(document).ready(function() {
    function autoPlayTabs(tabTitle1, tabTitle2, tabTitle3, tabTitle4, tabContent1, tabContent2, tabContent3, tabContent4, tabLength, tabTitleMobile1, tabTitleMobile2, tabTitleMobile3, tabTitleMobile4) {
        var actualTabLength = tabLength * 4;
        var tabContainer = jQuery('.elementor-tabs');
        var allTabs = jQuery('.elementor-tabs .elementor-tabs-wrapper .elementor-tab-title');
        var allContent = jQuery('.elementor-tabs .elementor-tabs-content-wrapper .elementor-tab-content');
        var initialTabTimer = null;
        var tabTimer = null;

        tabTitle1.addClass('active'); tabContent1.addClass('active');

        console.log('Setting initialTabTimer');
        initialTabTimer = setTimeout(function(){
            tabTitle1.removeClass('active'); tabContent1.removeClass('active');
            tabTitle2.addClass('active'); tabContent2.addClass('active');

            console.log("Setting Timeout2");
            setTimeout(function(){
                tabTitle2.removeClass('active'); tabContent2.removeClass('active');
                tabTitle3.addClass('active'); tabContent3.addClass('active');

                console.log("Setting Timeout3");
                setTimeout(function(){
                    tabTitle3.removeClass('active'); tabContent3.removeClass('active');
                    tabTitle4.addClass('active'); tabContent4.addClass('active');
                    console.log("Executing Timeout3 Function");
                }, tabLength);
            }, tabLength);
        }, tabLength);

        console.log("Setting tabTimer");
        tabTimer = setInterval(function(){
            tabTitle4.removeClass('active'); tabContent4.removeClass('active');
            tabTitle1.addClass('active'); tabContent1.addClass('active');

            console.log("Setting TimeoutB");
            setTimeout(function(){
                tabTitle1.removeClass('active'); tabContent1.removeClass('active');
                tabTitle2.addClass('active'); tabContent2.addClass('active');

                console.log("Setting TimeoutC");
                setTimeout(function(){
                    tabTitle2.removeClass('active'); tabContent2.removeClass('active');
                    tabTitle3.addClass('active'); tabContent3.addClass('active');

                    console.log("Setting TimeoutD");
                    setTimeout(function(){
                        tabTitle3.removeClass('active'); tabContent3.removeClass('active');
                        tabTitle4.addClass('active'); tabContent4.addClass('active');
                        console.log("Executing TimeoutD Function");
                    }, tabLength);
                }, tabLength);
            }, tabLength);
        }, actualTabLength);

        allTabs.click(function() {
            if (initialTabTimer !== null) {
               clearTimeout(initialTabTimer);
               initialTabTimer = null;
               console.log("Cleared initialTabTimer");
            }

            if (tabTimer !== null) {
               clearInterval(tabTimer);
               tabTimer = null;
               console.log("Cleared tabTimer");
            } else {
                console.log("Did not need to clear tabTimer");
            }
            
            allTabs.removeClass('active');
            allContent.removeClass('active');
            tabContainer.addClass('tabsManual');
        });
    }

    if(homeTabTitle1.length > 0){
    console.log("Calling AutoPlayTabs Homepage");
    autoPlayTabs(homeTabTitle1,homeTabTitle2,homeTabTitle3,homeTabTitle4,homeTabContent1,homeTabContent2,homeTabContent3,homeTabContent4,homeTabLength);
    }
});

下面是一个 console.log,它记录了从它工作到中断到修复自身的每个 setTimeout:

Calling AutoPlayTabs Homepage
Setting initialTabTimer
Setting tabTimer
Setting Timeout2
Setting Timeout3
Executing Timeout3 Function

//This console.log block ran 30 times without error//
Setting TimeoutB
Setting TimeoutC
Setting TimeoutD
Executing TimeoutD Function
//This console.log block ran 30 times without error//

//It Breaks here after a total of 24 minutes//
Setting TimeoutB
Setting TimeoutC
Setting TimeoutD
Setting TimeoutB //For some reason TimeoutB has been fired again
Executing TimeoutD Function

Setting TimeoutC
Setting TimeoutD
Setting TimeoutB
Executing TimeoutD Function

Setting TimeoutC
Setting TimeoutD
Executing TimeoutD Function

//It fixed itself here after 2.4 minutes//

Setting TimeoutB
Setting TimeoutC
Setting TimeoutD
Executing TimeoutD Function

标签: javascriptjquerysetinterval

解决方案


如果您只是将逻辑简化为只运行一个间隔,那么您所有的同步问题都会消失

 const tabs = [
  {title: tabTitle1, content: tabContent1},
  {title: tabTitle2, content: tabContent2},
  {title: tabTitle3, content: tabContent3},
  {title: tabTitle4, content: tabContent4}
 ];
 
 let curr = 0;
 let tab = tabs[curr];
 tab.title.addClass("active");
 tab.content.addClass("active");

 var timerInterval = setInterval(function(){     
        tab.title.removeClass("active");
        tab.content.removeClass("active");
        curr = ++curr % tabs.length;
        tab = tabs[curr];
        tab.title.addClass("active");
        tab.content.addClass("active");
 }, tabLength);

活生生的例子

jQuery(document).ready(function() {
  function autoPlayTabs(tabTitle1, tabTitle2, tabTitle3, tabTitle4, tabContent1, tabContent2, tabContent3, tabContent4, tabLength, tabTitleMobile1, tabTitleMobile2, tabTitleMobile3, tabTitleMobile4) {
    var actualTabLength = tabLength * 4;
    var tabContainer = jQuery('.elementor-tabs');
    var allTabs = jQuery('.elementor-tabs .elementor-tabs-wrapper .elementor-tab-title');
    var allContent = jQuery('.elementor-tabs .elementor-tabs-content-wrapper .elementor-tab-content');
    var initialTabTimer = null;
    var tabTimer = null;
    
    const tabs = [
        {title: tabTitle1, content: tabContent1},
      {title: tabTitle2, content: tabContent2},
      {title: tabTitle3, content: tabContent3},
      {title: tabTitle4, content: tabContent4}
     ];
     
     let curr = 0;
     let tab = tabs[curr]
     tab.title.addClass("active")
     tab.content.addClass("active");
     var timerInterval = setInterval(function(){
     
            tab.title.removeClass("active")
            tab.content.removeClass("active");
        curr = ++curr % tabs.length
            tab = tabs[curr]
        tab.title.addClass("active")
            tab.content.addClass("active");
     }, tabLength)
    

    allTabs.click(function() {
      if (initialTabTimer !== null) {
        clearTimeout(initialTabTimer);
        initialTabTimer = null;
      }

      if (tabTimer !== null) {
        clearInterval(tabTimer);
        tabTimer = null;
      }

      allTabs.removeClass('active');
      allContent.removeClass('active');
      tabContainer.addClass('tabsManual');
    });
  }

  if ($("#homeTabTitle1")) {
    autoPlayTabs($("#homeTabTitle1"), $("#homeTabTitle2"), $("#homeTabTitle3"), $("#homeTabTitle4"), $("#homeTabContent1"), $("#homeTabContent2"), $("#homeTabContent3"), $("#homeTabContent4"), 1000);
  }
});
.active { background-color:red }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="homeTabTitle1">
  homeTabTitle1
</div>
<div id="homeTabTitle2">
  homeTabTitle2
</div>
<div id="homeTabTitle3">
  homeTabTitle3
</div>
<div id="homeTabTitle4">
  homeTabTitle4
</div>
<div id="homeTabContent1">
  homeTabContent1
</div>
<div id="homeTabContent2">
  homeTabContent2
</div>
<div id="homeTabContent3">
  homeTabContent3
</div>
<div id="homeTabContent4">
  homeTabContent4
</div>

注意我没有连接你的“停止”逻辑,但你需要做的就是clearInterval(timerInterval)在你的click处理程序中。


推荐阅读