Setinterval 'tripping' Itself And Starting A 2nd Interval Timer
Solution 1:
If you just simplify your logic to only have a single interval running, all your syncronisation problems go away
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);
Live example
jQuery(document).ready(function() {
functionautoPlayTabs(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 }
<scriptsrc="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script><divid="homeTabTitle1">
homeTabTitle1
</div><divid="homeTabTitle2">
homeTabTitle2
</div><divid="homeTabTitle3">
homeTabTitle3
</div><divid="homeTabTitle4">
homeTabTitle4
</div><divid="homeTabContent1">
homeTabContent1
</div><divid="homeTabContent2">
homeTabContent2
</div><divid="homeTabContent3">
homeTabContent3
</div><divid="homeTabContent4">
homeTabContent4
</div>
Note I have not hooked up your "stop" logic, but all you need to do is clearInterval(timerInterval)
in your click
handler.
Solution 2:
As requested
Could you pop an updated answer of that using setInterval
You can refactor to a single setInterval(). The following is a concept - if your tabs are not next to each other in the HTML, then you can collate them up-front and loop through an array. You can also link your content to your tab using data-
attributes.
This also allows your use to change the "active" tab (eg by clicking on it) and it will "auto play" to the next one each time - but you might want to reset the timer in that case.
var interval_time = 250; // short time for demovar tabs = $(".tab");
// single setIntervalvar timer = setInterval(() => {
// get the currently active, so no need to store what that wasvar active = tabs.filter(".active");
active.removeClass("active");
// get the next tab, if none, then loop back to the firstvar next = active.next(".tab");
if (next.length == 0)
next = tabs.first();
next.addClass("active");
}, interval_time);
$("#stop").click(() =>clearInterval(timer))
/* can show / hide
.tab { display:none; }
.tab.active { display:block; }
*//* or show all the tabs at once */.tab { display:inline-block; color: #CCC; }
.tab.active { color: green }
<scriptsrc="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script><divclass='tab active'>tab 1</div><divclass='tab'>tab 2</div><divclass='tab'>tab 3</div><divclass='tab'>tab 4</div><br/><buttontype='button'id='stop'>stop</button>
Solution 3:
This is not setTimeout tripping up, it is setTimeout being called twice
To help document this, you could put console.log
s in to show when each timer is being started. For simplicity, I am also getting rid of all the class adding and removals.
I am also curious where homeTabTitle1
comes from - could you clarify?
jQuery(document).ready(function() {
functionautoPlayTabs(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;
console.log("Setting initialTabTimer")
initialTabTimer = setTimeout(function() {
console.log("Setting timer 2")
setTimeout(function() {
console.log("Setting timer 3")
setTimeout(function() {
console.log("Executing inner function 3")
}, tabLength);
}, tabLength);
}, tabLength);
console.log("Setting tabTimer")
tabTimer = setInterval(function() {
console.log("Setting timber B")
setTimeout(function() {
console.log("Setting timber C")
setTimeout(function() {
console.log("Setting timber D")
setTimeout(function() {
console.log("Executing inner function D")
}, tabLength);
}, tabLength);
}, tabLength);
}, actualTabLength);
allTabs.click(function() {
if (initialTabTimer !== null) {
clearTimeout(initialTabTimer);
initialTabTimer = null;
console.log("Cleared initialTabTimer");
} else {
console.log("Did not need to clear initialTabTimer");
}
if (tabTimer !== null) {
clearInterval(tabTimer);
tabTimer = null;
console.log("Cleared tabTimer");
} else {
console.log("Did not need to clear tabTimer");
}
});
}
if (homeTabTitle1) {
console.log("calling AutoPlayTabs")
autoPlayTabs(homeTabTitle1, homeTabTitle2, homeTabTitle3, homeTabTitle4, homeTabContent1, homeTabContent2, homeTabContent3, homeTabContent4, homeTabLength);
}
});
Why might document ready fire more than once?
As pointed out here:
jQuery $(document).ready () fires twice
The commonest cause is something being manipulated in the DOM that causes the document to be re-rendered. The answerer suggests a solution.
Why do some people call setTimeout "unreliable"?
I think they mean you cannot rely on when the callback function will be called. I think they unreasonably expect setTimeout to be able to magically cause Javascript to run the code exactly at the desired time. In reality, setTimer simply puts the task on a list of tasks to be run when the main program has run out of things to do.
Typically, on a web page, there is almost nothing for the Javascript interpreter to do after the page is initially rendered. In that case, the setTimeout
callbacks will be called at a reasonably accurate time.
However, if the web page has plenty of things for the Javascript interpreter to do, taking many seconds or even minutes of "thinking time" such as massive calculations, then setTimeout
will appear to be unreliable at a superficial assessment. However it is not really unreliable, it is doing what it should do, which is delaying the callback until there is both free time, and sufficient time has passed.
If the Javascript code calls asynchronous functions, then that potentially frees up the interpreter to look at setTimeout events. So if the web page becomes ready (from a jQuery point of view) but then has several seconds of communication with other sites to get database entries etc then, as long as those database calls are asynchronous, setTimeout is able to fire its callback if needed.
setInterval and setTimeout are different
"For some reason timeoutB has been fired again"
The reason is that it is a setInterval
, not a setTimeout
. Was that intentional? setInterval
will keep firing over and over.
Post a Comment for "Setinterval 'tripping' Itself And Starting A 2nd Interval Timer"