I'm trying to code my own timer from scratch. Complete noob here. I know there's a good amount of tutorials out there about building a timer, but from experience, whenever I use examples I don't really learn. Here's the code I come up with:
<p id="myTimer">Blank Text</p>
var timer = 60;
function updatePLEASE() {
timer--;
}
while (timer > 0){
console.log(timer);
document.getElementById("myTimer").innerHTML = timer;
setTimeout(updatePLEASE(), 1000); /* replicate wait 1 second */
}
When it runs, it shows "1". I thought it was returning a boolean value at first until I added the console.log and saw that the script does thankfully countdown from 60 down to 1. But, the script seems to only use setTimeout once.
Why doesn't the script wait 1000 ms before running the loop again? Or better question: Am I using the setTimeout function correctly?
setTimeout take function name and it will if not while and change the text within function.
var timer = 60;
function updatePLEASE() {
timer--;
if (timer > 0){
//console.log(timer);
document.getElementById("myTimer").innerHTML = timer;
setTimeout(updatePLEASE, 1000); /* replicate wait 1 second */
}
}
updatePLEASE();
<p id="myTimer">Blank Text</p>
setTimeout is async. Therefor you need something that will wait for that async operation to end.
You can do it in 2 ways:
1. wrap it with a "recursive" function.
So after 1 sec you call this function again and again until 0.
let timer = 60;
function updatePLEASE() {
timer--;
}
function countDownTimer() {
if (timer > 0) {
console.log(timer);
document.getElementById("myTimer").innerHTML = timer;
updatePLEASE();
setTimeout(countDownTimer, 1000); /* replicate wait 1 second */
}
}
countDownTimer();
<p id="myTimer">Blank Text</p>
2. Use await and Promise:
let timer = 60;
function updatePLEASE() {
timer--;
}
async function countDownTimer() {
while (timer > 0) {
console.log(timer);
document.getElementById("myTimer").innerHTML = timer;
await new Promise(resolve =>
setTimeout(() => {
updatePLEASE();
resolve();
}, 1000));
}
}
countDownTimer();
<p id="myTimer">Blank Text</p>
You have two problems with the code:
1) The while loop completes before any setTimeout is run. Just so you know: setTimeout is asynchronous. Maybe you should do some reading about sync vs async code in Javascript.
2) The first param of setTimeout is a function. You pass the result of the function.
setTimeout accept function name only or variable function, however by mistake u exciting it.
setTimeout(updatePLEASE(), 1000);
Correct:
setTimeout(updatePLEASE, 1000);
Note: Code is wrong. it will run while loop without the wait of setTimeout. Because setTimeout runs asynchronously in event-loop.
More: https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop
You can delay using async-await. but example is little complex. I will recommend use recursion for this case.
var timer = 60;
const delay = (fn) =>
new Promise((r) => {
fn();
setTimeout(r, 1000);
});
function updatePLEASE() {
timer--;
}
async function main() {
while (timer > 0) {
// delay 1 sec
console.log(timer)
await delay(updatePLEASE);
}
}
main();
Related
function tick() {
seconds_lapsed++; // Break point.
}
function countdown() {
while(!stopped || !is_paused()){
setTimeout(tick, 1000); // 1 second.
show_counter();
}
}
Could you tell me why the interpreter doesn't stop at the breakpoint? The while loop works, hava a look at the screenshot.
The while loop is a "busy" loop, i.e. it keeps the JavaScript engine busy, so it will not process anything that is waiting in one of its event/job queues. This means that the user interface does not get updated, no input can be processed, and events produced by setTimeout are not consumed. In this example, tick can only get executed if the currently running code finishes. So the while loop must end first.
You should let tick execute, and only then check the condition:
var stopped = true;
var seconds_lapsed = 0;
document.querySelector("button").addEventListener("click", function() {
stopped = !stopped;
seconds_lapsed = 0;
this.textContent = stopped ? "Start" : "Stop";
if (!stopped) countdown();
});
function show_counter() {
document.querySelector("span").textContent = seconds_lapsed;
}
function is_paused() {
return document.querySelector("input").checked;
}
function tick() {
seconds_lapsed++;
}
function countdown() {
show_counter();
setTimeout(function () {
if (stopped) return; // stop the loop
if (!is_paused()) tick();
countdown(); // <--- this is the "loop"
}, 1000);
}
Seconds elapsed: <span>0</span><br>
<input type="checkbox">Paused<br>
<button>Start</button>
the following example might help you accomplish what you are after. Distinguish between setInterval() and setTimeout()
Basically the docs say:
setTimeout executes a function or specified piece of code once the timer expires.
setInterval repeatedly calls a function or executes a code snippet, with a fixed time delay between each call.
So if you use setInterval you don't need a while loop inside because it is already called "repeatedly"
var counter = $('#counter');
var stopped = false;
var seconds_lapsed=0;
var myInterval;
function tick() {
if(stopped) {
clearInterval(myInterval);
show_counter('FINISHED');
return;
}
show_counter(seconds_lapsed++);
}
function show_counter(message){
counter.html(message);
}
function countdown() {
myInterval = setInterval(tick, 1000);
}
function endCountdown(timeout) {
let timeoutId = setTimeout(function(){
stopped = true;
clearTimeout(timeoutId)
}, timeout);
}
countdown(); // start the countdown
endCountdown(5000); // ends the countdown after 5000 ms => 5sec
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="counter">counter</div>
Hello is there a way to call a function with setInterval and clear the interval later?
Example: When I write in a chat !start the interval function should start with a interval. And when I write !stop in the chat the function with the interval on it should stop.
This is my function:
function abb(channel){
console.log('Auto-Ban-Bot Timer running...')
getChannelViewers(channel.replace('#','')).then(
promise => {
var vierwernames = promise.chatters.viewers;
vierwernames.forEach(element => {
checkFriendlyBots(element)
});
}
);
}
I've tried many things but only got the !start command working, not the !stop command.
This is exactly what clearInterval() method does. It clears a timer set with the setInterval() method.
Check out this example:
const interval = setInterval(myTimer, 1000);
let i = 0;
function myTimer() {
console.log(i++);
if (i === 5){
stop();
}
}
function stop() {
clearInterval(interval);
}
I want to run a delay function for five seconds in JavaScript which will print "Hello" in the console after every second for five times.
Similar Python Code:
from time import delay
for I in range(5):
print("Hello")
delay(1)
The above code will print "Hello" five times with one second delay between each print.
Now I want to do similar kind of operation in JS.
Now in JS we have setTimeout function which will call a function after after a specified time. The following code will print "Hello" in the console after 1 second interval.
setTimeout(function(){
console.log("Hello");
}, 1000);
How can I run this code that will print 'Hello' in the console five times with an one second delay between each print?
NB: I tried to pass this function inside a for loop, but it did not work.
Try like this:
var count = 5;
printWithDelay();
function printWithDelay() {
setTimeout(function() {
console.log("Hello");
count--;
if (0 < count) {
printWithDelay();
};
}, 1000);
};
In JavaScript, 'setTimeout' runs after the code that follows it, so the next iteration of the loop needs to be called from within the callback function for this to work.
JavaScript, unlike PHP and Python, is asynchronous. The event loop is sensitive to anything that blocks it. However, there are ways to achieve what you want.
setInterval
With setInterval, you can build a wrapper it and use it.
function repeatFunction(func, delay, repeat) {
let counter = 0;
let interval = setInterval(() => {
if (repeat !== counter) {
func();
counter++;
} else {
clearInterval(interval)
}
}, delay);
}
repeatFunction(() => console.log(5), 1000, 4)
async/await syntax
The other option is using async/await with Promises (recommended)
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
(async() => {
for (let i = 0; i < 5; i++) {
console.log(i);
await sleep(1000);
}
console.log('done')
})();
Use setInterval, this should get your job done!
const test = setInterval(() => console.log("Hello"), 1000);
And then after 5seconds remove interval
setTimeout( () => clearInterval(test), 5000)
const test = setInterval(() => document.body.innerText += "Hello", 1000);
setTimeout( () => clearInterval(test), 5000);
NOTE: The first console.log() will happen after a second, if you want it immediately just put one console.log() outside the setInterval.
My setTimeout() function works, but my clearTimeout() is not working. Even though I have an 'if' statement that's supposed to run the clearTimeout function once my variable 'secs' is less than 0, the timer keeps counting down into negative numbers. When I type my variable name, 'secs' into the console, I get undefined, even though it's defined as a parameter in the function called by my setTimeout. I don't know what I'm doing wrong. Can anyone help, please?
My full code is at https://codepen.io/Rburrage/pen/qBEjXmx;
Here's the JavaScript snippet:
function startTimer(secs, elem) {
t = $(elem);
t.innerHTML = "00:" + secs;
if(secs<0) {
clearTimeout(countDown);
}
secs--;
//recurring function
countDown = setTimeout('startTimer('+secs+',"'+elem+'")', 1000);
}
Add a condition to call recursive function like below.
if (secs < 0) {
secs = secsInput;
}
//recurring function
countDown = setTimeout('startTimer('+secs+',"'+elem+'")', 1000);
For a countdown timer, I would recommend using setInterval and clearInterval instead. setInterval will repeatedly run the callback function for you. It might look like this:
let countdown;
function startTimer(secs, elem) {
countdown = setInterval(function(){
t = $(elem);
t.innerHTML = "00:" + secs;
secs--
if (secs < 0) {
clearInterval(countdown);
}
}, 1000);
}
By the time you call clearTimeout(countDown), countDown refers to the previous timeout, that already timed out. It will not stop the one yet to start. You could just not re set the timeout, like
if(!/*finished*/) setTimeout(startTimer, 1000, secs, elem);
In your case, it's more convenient to use setInterval and clearInterval.
To keep the setTimeout and clearTimeout functions, you should add return in the if statement.
function startTimer(secs, elem) {
t = $(elem);
t.innerHTML = "00:" + secs;
if(secs<0) {
clearTimeout(countDown);
return;
}
secs--;
//recurring function
countDown = setTimeout('startTimer('+secs+',"'+elem+'")', 1000);
}
So there are 4 events in my opinion that will have to be addressed by the timer:
The quiz starts
The quiz ends
The timer runs out
The player answers a question
This can be solved by a function returning an object with some options.
The createTimer can be used to set the parameters for the timer.
Point 1. would be timer.start() --> will start a timer with the parameters
Point 3. can be addressed with the callback that will be called if the timer runs out --> createTimer(5,'display', ()=>{ // your code goes here })
Point 2. can be achieved with --> timer.stop()
Point 4. is needed when the timer needs to be reset without running out timer.reset()
Further on the interval is not in the global scope so you could have multiple timers with different settings and they wouldn't interfere with each other
// function for creating the timer
function createTimer(seconds, cssSelector, callbackOnTimeout) {
// interval the timer is running
let interval;
// the html node where innerText will be set
const display = document.getElementById(cssSelector)
// original seconds passt to createTimer needed for restart
const initSec = seconds
// starting or continuing the interval
function start() {
// setting interval to the active interval
interval = setInterval(() => {
display.innerText = `00:${seconds}`;
--seconds;
if (seconds < 0) {
// calling restart and callback to restart
callbackOnTimeout()
restart()
}
}, 1000);
}
// just stopping but not resetting so calling start will continue the timer
// player takes a break
function stop(){
clearInterval(interval)
}
// opted for a restart and not only a reset since it seemed more appropriate for your problem
function restart(){
clearInterval(interval)
seconds = initSec
start()
}
// returning the object with the functions
return {
start: start,
stop: stop,
restart: restart
}
}
// example for creating a timer
const timer1 = createTimer(5,'display',()=>{
console.log(`you where to slow ohhh...`)
})
// calling the timer
timer1.start()
Using setTimeout() it is possible to launch a function at a specified time:
setTimeout(function, 60000);
But what if I would like to launch the function multiple times? Every time a time interval passes, I would like to execute the function (every 60 seconds, let's say).
If you don't care if the code within the timer may take longer than your interval, use setInterval():
setInterval(function, delay)
That fires the function passed in as first parameter over and over.
A better approach is, to use setTimeout along with a self-executing anonymous function:
(function(){
// do some stuff
setTimeout(arguments.callee, 60000);
})();
that guarantees, that the next call is not made before your code was executed. I used arguments.callee in this example as function reference. It's a better way to give the function a name and call that within setTimeout because arguments.callee is deprecated in ecmascript 5.
use the
setInterval(function, 60000);
EDIT : (In case if you want to stop the clock after it is started)
Script section
<script>
var int=self.setInterval(function, 60000);
</script>
and HTML Code
<!-- Stop Button -->
Stop
A better use of jAndy's answer to implement a polling function that polls every interval seconds, and ends after timeout seconds.
function pollFunc(fn, timeout, interval) {
var startTime = (new Date()).getTime();
interval = interval || 1000;
(function p() {
fn();
if (((new Date).getTime() - startTime ) <= timeout) {
setTimeout(p, interval);
}
})();
}
pollFunc(sendHeartBeat, 60000, 1000);
UPDATE
As per the comment, updating it for the ability of the passed function to stop the polling:
function pollFunc(fn, timeout, interval) {
var startTime = (new Date()).getTime();
interval = interval || 1000,
canPoll = true;
(function p() {
canPoll = ((new Date).getTime() - startTime ) <= timeout;
if (!fn() && canPoll) { // ensures the function exucutes
setTimeout(p, interval);
}
})();
}
pollFunc(sendHeartBeat, 60000, 1000);
function sendHeartBeat(params) {
...
...
if (receivedData) {
// no need to execute further
return true; // or false, change the IIFE inside condition accordingly.
}
}
In jQuery you can do like this.
function random_no(){
var ran=Math.random();
jQuery('#random_no_container').html(ran);
}
window.setInterval(function(){
/// call your function here
random_no();
}, 6000); // Change Interval here to test. For eg: 5000 for 5 sec
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="random_no_container">
Hello. Here you can see random numbers after every 6 sec
</div>
setInterval(fn,time)
is the method you're after.
You can simply call setTimeout at the end of the function. This will add it again to the event queue. You can use any kind of logic to vary the delay values. For example,
function multiStep() {
// do some work here
blah_blah_whatever();
var newtime = 60000;
if (!requestStop) {
setTimeout(multiStep, newtime);
}
}
Use window.setInterval(func, time).
A good example where to subscribe a setInterval(), and use a clearInterval() to stop the forever loop:
function myTimer() {
}
var timer = setInterval(myTimer, 5000);
call this line to stop the loop:
clearInterval(timer);
Call a Javascript function every 2 second continuously for 10 second.
var intervalPromise;
$scope.startTimer = function(fn, delay, timeoutTime) {
intervalPromise = $interval(function() {
fn();
var currentTime = new Date().getTime() - $scope.startTime;
if (currentTime > timeoutTime){
$interval.cancel(intervalPromise);
}
}, delay);
};
$scope.startTimer(hello, 2000, 10000);
hello(){
console.log("hello");
}
function random(number) {
return Math.floor(Math.random() * (number+1));
}
setInterval(() => {
const rndCol = 'rgb(' + random(255) + ',' + random(255) + ',' + random(255) + ')';//rgb value (0-255,0-255,0-255)
document.body.style.backgroundColor = rndCol;
}, 1000);
<script src="test.js"></script>
it changes background color in every 1 second (written as 1000 in JS)
// example:
// checkEach(1000, () => {
// if(!canIDoWorkNow()) {
// return true // try again after 1 second
// }
//
// doWork()
// })
export function checkEach(milliseconds, fn) {
const timer = setInterval(
() => {
try {
const retry = fn()
if (retry !== true) {
clearInterval(timer)
}
} catch (e) {
clearInterval(timer)
throw e
}
},
milliseconds
)
}
here we console natural number 0 to ......n (next number print in console every 60 sec.) , using setInterval()
var count = 0;
function abc(){
count ++;
console.log(count);
}
setInterval(abc,60*1000);
I see that it wasn't mentioned here if you need to pass a parameter to your function on repeat setTimeout(myFunc(myVal), 60000); will cause an error of calling function before the previous call is completed.
Therefore, you can pass the parameter like
setTimeout(function () {
myFunc(myVal);
}, 60000)
For more detailed information you can see the JavaScript garden.
Hope it helps somebody.
I favour calling a function that contains a loop function that calls a setTimeout on itself at regular intervals.
function timer(interval = 1000) {
function loop(count = 1) {
console.log(count);
setTimeout(loop, interval, ++count);
}
loop();
}
timer();
There are 2 ways to call-
setInterval(function (){ functionName();}, 60000);
setInterval(functionName, 60000);
above function will call on every 60 seconds.