I'm trying to create an if statement which sets a timeout when a function is called:
var timeOutID;
if (//function1 is called) {
timeOutID = setTimeout(function1, 30000);
}
The idea is that the function gets repeatedly called after 30 seconds, but the timeout can be reset at any point if function is called (e.g. a button is clicked). How can this be accomplished? Many thanks.
When you want to do something repeating at a set interval, setInterval may be a better way to go. It will call a method after every X milliseconds if you don't cancel it.
Here is a basic example of reseting the interval whenever a button is clicked. In the log you will see that when you don't click the button a new log line appears every 5 seconds. When you click on the button the next line will take longer to appear after which they will appear again every 5 seconds.
I used 5 seconds instead of 30 so you don't have to wait that long to see the effect of pressing the button.
const
resetButton = document.getElementById('reset'),
confirmationMessage = document.getElementById('confirmation'),
intervalDuration = 5000;
let
intervalId = null
lastCallTime = new Date();
function resetInterval() {
// Stop the current interval...
clearInterval(intervalId);
// and start a new interval.
startInterval();
}
function startInterval() {
// Set an interval, it will call logTimeSinceLastCall every X seconds.
intervalId = setInterval(() => {
logTimeSinceLastCall();
}, intervalDuration);
}
function logTimeSinceLastCall() {
// Hide the message that the interval has been reset.
confirmationMessage.classList.add('hidden');
const
// Get the current time.
now = new Date(),
// Substract the time from the last call, the difference is the number of milliseconds passed.
diff = now.getTime() - lastCallTime.getTime();
// Log a line to the console for some visual feedback.
console.log(`Last call was ${diff}ms ago`);
// Update the time stamp of the last time this method was called.
lastCallTime = now;
}
function onResetClicked(event) {
resetInterval();
// Show the message that the button has been clicked.
confirmationMessage.classList.remove('hidden');
}
// Whenever the button is clicked, reset the interval.
resetButton.addEventListener('click', onResetClicked);
// Start the initial interval.
startInterval();
.hidden {
display: none;
}
<button type="button" id="reset">Reset interval</button>
<p id="confirmation" class="hidden">
The interval has been reset.
</p>
Related
I'm building a chrome addon in manifest v2. I have an interval that runs every minute. Inside it, I have a function that supposed to reload the page will reload every 3 minutes if a boolean is false. If it is true, the timer of the 3 minutes need to reset itself.
For some reason, when I'm setting the timer and logging it, it is stuck at '1'. It will move only when I will consantly set it again - which by theory should reset it but nope - it just continues.
When I call for clearTimeout, nothing happens - the timer stays the same. Even if I try to equel the timer variable into a null, it's still continues regularly.
This is the code, hope that you could help me figure this out:
var timerLoop = [].
var audioPlayed = false;
var timer = null;
function clearTimerLoop(){
for ( var i = 0; i < timerLoop.length; ++i ){
clearTimeout( timerLoop[i] );
timerLoop[i] = null; //Tried here to make it a null, no success
}
timerLoop = []; //Tried here to remove everything from the array, no success
console.log("Timer cleared");
}
function startTimer(){
timer = window.setTimeout(refreshPage, 180000); /* reload every 3 minutes */
timerLoop.push(timer);
console.log("Timer created");
}
loopInterval = setInterval(function(){loopChecker();}, 60000);
function loopChecker(){
if(audioPlayed){
clearTimerLoop()
timer = null;
audioPlayed = false;
}
if(!audioPlayed && timer == null){
startTimer();
console.log("Refresh timer running (" + timerLoop[0] + ")");
}
console.log(timer);
}
Thanks in advance.
As you can see I am resetting the timer as much as I can but nothing happens. In addition, the timer is stuck on 1 unless I set it again in every timer loopChecker() runs, and again - this should reset it but it continues.
I thought maybe every run sets a new timer so I created an array that pushes the timer each time it's created and then when I want to clear, every timer is cleared. Didn't help.
Instead of doing all of that, you can just do something like this:
timer = null
if (boolean == false) {
timer = setInterval(() => {
window.location.reload();
}, 180000)
...
}
else {
clearInterval(timer);
timer = null; // stops page reloading every 3 min by deleting setInterval and its callback
...
}
Hi Everyone I know it is basic and silly to ask but this question is eating me up .
If I have a below following code .
var timerVal = 900000
function myFunction() {
setTimeout(function(){ alert("Hello"); }, timerVal);
}
myFunction()
As per the above code an alert will come at 15 mins . But after ten minutes I thought to extend it for more 5 mins by changing the value of timerVal to 1200000. Now would the alert will come after another 10 mins . i.e. total 20 mins after the alert will come or it will come after 15 mins of the completion .
Suppose the code is like this :
var timerVal = 900000
function myFunction() {
setTimeout(function(){ alert("Hello"); }, timerVal);
}
function change(){
setTimeout(function(){
timerVal = 1200000;
},60000);
}
myFunction();
change();
Can Anyone give let me know what will be the result and brief description why ?
The result will be that the timer will be executed at the 900000 millisecond mark, although you have tried to change it to 1200000 millisecond by changing the value of the timerVal variable.
This is because in JavaScript it is pass by value and since you have passed 900000 initially, the timer is already queued at 900000 and hence cannot be altered by changing the value of the timerVal variable again.
So this code, is simply making the timerVal point to the new number 1200000 not really changing the timeout set earlier:
function change(){
setTimeout(function(){
timerVal = 1200000; //timerVal reference is pointing to a new number
}, 60000);
}
To really change the timer behavior you need to clear the timeout using the id returned by the setTimeout call and create another one with the new timeout value.
let timerVal = 9000;
function myFunction() {
return setTimeout(function(){ alert("Hello"); }, timerVal); //returning the id
}
function change(id, newVal){
clearTimeout(id); //clearing the previous timer using the id
setTimeout(function(){ alert("Hello"); }, newVal);
}
let id = myFunction();
change(id, 5000);
Well, in general to be able to "extend" a timer, you'll need to cancel it (using clearTimeout), and re-create it. For this you'll need to keep track of how long has elapsed since it originally started and calculate a new time.
The code below demonstrates a function extendableTimeout which you can use like the normal setTimeout, except it returns an object with an extend function you can use for your purpose.
The demo has 2 button, the first starts an action delayed for 5s. Clicking the extend button extends the timeout by another 5 seconds. You can compare clicking the extend or not to see the timings.
function extendableTimeout(fn, time){
var id = setTimeout(fn, time);
var timeStart = new Date();
return {
timerId: id,
extend: function(time){
clearTimeout(id);
var elapsed = new Date() - timeStart;
var newTime = time - elapsed;
setTimeout(fn,newTime);
}
}
}
var myTimer;
$('#start').on("click", function(){
console.log("Started at " + new Date());
myTimer = extendableTimeout(() => console.log("Finished at " + new Date()), 5000);
})
$("#extend").on("click", function(){
myTimer.extend(10000);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button id="start">Start</button>
<button id="extend"> + 5s </button>
AFAIU, you cannot extend the time of a setTimeout. What you can do is stopping it from executing, and create another setTimeout with the new value. Like this:
var timer = setTimeout(()=>console.log("first"), 2000);
clearTimeout(timer);
var timer = setTimeout(()=>console.log("second"), 2000);
You cannot extend it because the timer is created with the value the variable had at the time of creation event. It's not a reference that can be evaluated from time to time. It's a fixed value that is evaluated only on creation time.
I have two functions that display minutes and seconds. Inside the functions I'm using an IIFE with a setTimeout to calculate the time. After getting this, having a hard time figuring out how I could pause the display if pause button is clicked.
The timer works fine and displays correctly.
I realize this is probably not a good way to do it, but I spent so much time (trying to learn how to use IIFE) that I don't want to give up. If I have to, then I will scratch it.
Update - This timer will be getting input from the user. It might be 25 minutes. I want it to start counting down from there until it reaches 0, and the user able to pause at anytime.
let convertToSeconds = document.getElementById('timeValue').value * 60;
let seconds = 60;
function secondsCounter(time) {
// let flag = document.getElementById('pauseButton').value;
for (let i = seconds; i > 0; i--) {
(function(x) {
setTimeout(function() {
let remaining = seconds - x;
document.getElementById('displaySeconds').innerHTML = remaining;
console.log(remaining);
}, i * 1000);
})(i);
}
}
function counter() {
for (let i = convertToSeconds; i > 0; i--) {
(function(minutes) {
setTimeout(function() {
let remaining = Math.floor((convertToSeconds - minutes) / 60);
document.getElementById('displayMinutes').innerHTML = remaining;
console.log(remaining);
}, i * 1000);
setTimeout(function() {
secondsCounter(seconds);
}, i * 60000);
})(i);
}
secondsCounter(seconds);
}
I've tried a couple of things.
Using a flag and if statement around document.getElementById('displaySeconds').innerHTML = remaining; so if my pause button is clicked, the flag changes, and another setTimeout (10 minutes) is triggered. Doesn't stop the countdown on the DOM, it keeps going. I just wanted to see some reaction, but nothing happened. Something like:
function secondsCounter(time) {
let flag = document.getElementById('pauseButton').value;
for (let i = seconds; i > 0; i--) {
(function(x) {
setTimeout(function() {
let remaining = seconds - x;
if (flag === 'yes') {
document.getElementById('displaySeconds').innerHTML = remaining;
console.log(remaining);
} else {
setTimeout(function() {
console.log(remaining);
}, 10000);
}
}, i * 1000);
})(i);
}
}
Using a setInterval and clearInterval that didn't do anything.
Is this possible? Not sure where else to look. Thank you
You can't stop/pause a setTimeout or clearTimeout without making a reference to the timer, storing it and then calling clearTimeout(timer) or clearInterval(timer).
So, instead of: setTimeout(someFunciton)
You need: timer = setTimeout(someFunciton)
And, the timer variable needs to be declared in a scope that is accessible to all functions that will use it.
See setTimeout() for details.
Without a reference to the timer, you will not be able to stop it and that's caused you to go on a wild goose chase for other ways to do it, which is overthinking what you actually need.
In the end, I think you should just have one function that does all the counting down so that you only have one timer to worry about.
Lastly, you can use the JavaScript Date object and its get / set Hours, Minutes and Seconds methods to take care of the reverse counting for you.
(function() {
// Ask user for a time to start counting down from.
var countdown = prompt("How much time do you want to put on the clock? (hh:mm:ss)");
// Take that string and split it into the HH, MM and SS stored in an array
var countdownArray = countdown.split(":")
// Extract the individual pieces of the array and convert to numbers:
var hh = parseInt(countdownArray[0],10);
var mm = parseInt(countdownArray[1],10);
var ss = parseInt(countdownArray[2],10);
// Make a new date and set it to the countdown value
var countdownTime = new Date();
countdownTime.setHours(hh, mm, ss);
// DOM object variables
var clock = null, btnStart = null, btnStop = null;
// Make a reference to the timer that will represent the running clock function
var timer = null;
window.addEventListener("DOMContentLoaded", function () {
// Make a cache variable to the DOM element we'll want to use more than once:
clock = document.getElementById("clock");
btnStart = document.getElementById("btnStart");
btnStop = document.getElementById("btnStop");
// Wire up the buttons
btnStart.addEventListener("click", startClock);
btnStop.addEventListener("click", stopClock);
// Start the clock
startClock();
});
function startClock() {
// Make sure to stop any previously running timers so that only
// one will ever be running
clearTimeout(timer);
// Get the current time and display
console.log(countdownTime.getSeconds());
countdownTime.setSeconds(countdownTime.getSeconds() - 1);
clock.innerHTML = countdownTime.toLocaleTimeString().replace(" AM", "");
// Have this function call itself, recursively every 900ms
timer = setTimeout(startClock, 900);
}
function stopClock() {
// Have this function call itself, recursively every 900ms
clearTimeout(timer);
}
}());
<div id="clock"></div>
<button id="btnStart">Start Clock</button>
<button id="btnStop">Stop Clock</button>
How can I make a function, and have it run/refresh every (second) once in a while based on a timer? I'm trying to run a function and it needs to be updated to check if a parameter is checked.
function checkTime() {
if(document.getElementById("time").innerHTML === "12:00:00 PM") {
alert("It's noon!");
}
}
This can be accomplished by using setInterval(). I am using something similar for this; I made a timer that shows the time that my period ends (in school) and also shows the current time, and when the time matches the period ends time, it should change to the next period automatically. With your example, you can do something like this:
//init function
function checkTime() {
//check if its noon
if(document.getElementById("time").innerHTML === "12:00:00 PM") {
//alert
alert("It's noon!");
}
}
//set the interval
setInterval(function() {
//execute code
checkTime();
}, /* every 5 seconds, or 5000 milliseconds */ 5000);
How could I accurately run a function when the minute changes? Using a setInterval could work if I trigger it right when the minute changes. But I'm worried setInterval could get disrupted by the event-loop in a long-running process and not stay in sync with the clock.
How can I run a function accurately when the minute changes?
First off, you should use setInterval for repeating timers, since it (tries to) guarantee periodic execution, i.e. any potential delays will not stack up as they will with repeated setTimeout calls. This will execute your function every minute:
var ONE_MINUTE = 60 * 1000;
function showTime() {
console.log(new Date());
}
setInterval(showTime, ONE_MINUTE);
Now, what we need to do is to start this at the exact right time:
function repeatEvery(func, interval) {
// Check current time and calculate the delay until next interval
var now = new Date(),
delay = interval - now % interval;
function start() {
// Execute function now...
func();
// ... and every interval
setInterval(func, interval);
}
// Delay execution until it's an even interval
setTimeout(start, delay);
}
repeatEvery(showTime, ONE_MINUTE);
This may be an idea. The maximum deviation should be 1 second. If you want it to be more precise, lower the milliseconds of setTimeout1.
setTimeout(checkMinutes,1000);
function checkMinutes(){
var now = new Date().getMinutes();
if (now > checkMinutes.prevTime){
// do something
console.log('nextminute arrived');
}
checkMinutes.prevTime = now;
setTimeout(checkChange,1000);
}
1 But, see also this question, about accuracy of timeouts in javascript
You can try to be as accurate as you can, setting a timeout each X milliseconds and check if the minute has passed and how much time has passed since the last invocation of the function, but that's about it.
You cannot be 100% sure that your function will trigger exactly after 1 minute, because there might be something blocking the event-loop then.
If it's something vital, I suggest using a cronjob or a separate Node.js process specifically for that (so you can make sure the event loop isn't blocked).
Resources:
http://www.sitepoint.com/creating-accurate-timers-in-javascript/
I've put up a possible solution for you:
/* Usage:
*
* coolerInterval( func, interval, triggerOnceEvery);
*
* - func : the function to trigger
* - interval : interval that will adjust itself overtime checking the clock time
* - triggerOnceEvery : trigger your function once after X adjustments (default to 1)
*/
var coolerInterval = function(func, interval, triggerOnceEvery) {
var startTime = new Date().getTime(),
nextTick = startTime,
count = 0;
triggerOnceEvery = triggerOnceEvery || 1;
var internalInterval = function() {
nextTick += interval;
count++;
if(count == triggerOnceEvery) {
func();
count = 0;
}
setTimeout(internalInterval, nextTick - new Date().getTime());
};
internalInterval();
};
The following is a sample usage that prints the timestamp once every minute, but the time drift is adjusted every second
coolerInterval(function() {
console.log( new Date().getTime() );
}, 1000, 60);
It's not perfect, but should be reliable enough.
Consider that the user could switch the tab on the browser, or your code could have some other blocking tasks running on the page, so a browser solution will never be perfect, it's up to you (and your requirements) to decide if it's reliable enough or not.
Tested in browser and node.js
sleeps until 2 seconds before minute change then waits for change
you can remove logging as it gets pretty cluttered in log otherwise
function onMinute(cb,init) {
if (typeof cb === 'function') {
var start_time=new Date(),timeslice = start_time.toString(),timeslices = timeslice.split(":"),start_minute=timeslices[1],last_minute=start_minute;
var seconds = 60 - Number(timeslices[2].substr(0,2));
var timer_id;
var spin = function (){
console.log("awake:ready..set..");
var spin_id = setInterval (function () {
var time=new Date(),timeslice = time.toString(),timeslices = timeslice.split(":"),minute=timeslices[1];
if (last_minute!==minute) {
console.log("go!");
clearInterval(spin_id);
last_minute=minute;
cb(timeslice.split(" ")[4],Number(minute),time,timeslice);
console.log("snoozing..");
setTimeout(spin,58000);
}
},100);
};
setTimeout(spin,(seconds-2)*1000);
if (init) {
cb(timeslice.split(" ")[4],Number(start_minute),start_time,timeslice,seconds);
}
}
}
onMinute(function (timestr,minute,time,timetext,seconds) {
if (seconds!==undefined) {
console.log("started waiting for minute changes at",timestr,seconds,"seconds till first epoch");
} else {
console.log("it's",timestr,"and all is well");
}
},true);
My first thought would be to use the Date object to get the current time. This would allow you to set your set interval on the minute with some simple math. Then since your worried about it getting off, every 5-10 min or whatever you think is appropriate, you could recheck the time using a new date object and readjust your set interval accordingly.
This is just my first thought though in the morning I can put up some code(its like 2am here).
This is a fairly straightforward solution ... the interval for the timeout is adjusted each time it's called so it doesn't drift, with a little 50ms safety in case it fires early.
function onTheMinute(callback) {
const remaining = 60000 - (Date.now() % 60000);
setTimeout(() => {
callback.call(null);
onTheMinute(callback);
}, remaining + (remaining < 50 ? 60000 : 0));
}
Here's yet another solution based on #Linus' post and #Brad's comment. The only difference is it's not working by calling the parent function recursively, but instead is just a combination of setInterval() and setTimeout():
function callEveryInterval(callback, callInterval){
// Initiate the callback function to be called every
// *callInterval* milliseconds.
setInterval(interval => {
// We don't know when exactly the program is going to starts
// running, initialize the setInterval() function and, from
// thereon, keep calling the callback function. So there's almost
// surely going to be an offset between the host's system
// clock's minute change and the setInterval()'s ticks.
// The *delay* variable defines the necessary delay for the
// actual callback via setTimeout().
let delay = interval - new Date()%interval
setTimeout(() => callback(), delay)
}, callInterval, callInterval)
}
Small, maybe interesting fact: the callback function only begins executing on the minute change after next.
The solution proposed by #Linus with setInterval is in general correct, but it will work only as long as between two minutes there are exactly 60 seconds. This seemingly obvious assumption breaks down in the presence of a leap second or, probably more frequently, if the code runs on a laptop that get suspended for a number of seconds.
If you need to handle such cases it is best to manually call setTimeout adjusting every time the interval. Something like the following should do the job:
function repeatEvery( func, interval ) {
function repeater() {
repeatEvery( func, interval);
func();
}
var now = new Date();
var delay = interval - now % interval;
setTimeout(repeater, delay);
}