Repeat function execution for n seconds - javascript

I want to run x function for n seconds. What I tried:
var stop = false;
setTimeout(function(){stop = true}, n);
while(!stop) x();
but this didn't work... As I understood the reason is that setTimeout waiting until no task is running and then executes the function. Is that right?
Another way to do this is like this:
var stop = false, started = Date.now();
while(!stop) {
if((Date.now() - started) > n) stop = true;
else x();
}
Is there any other better way?

var stop = false;
setTimeout(function(){stop = true}, n);
var interval = setInterval(function(){
if(!stop){x();}else{clearInterval(interval);}
}, 0);
the while statement will block the timeout function, if you don't mind using setInterval, you can do it like this.

i will do like this
var t = new Date().getSeconds() + 10; // 10 seconds
while(new Date().getSeconds() <= t)
{
//loop
}

You can schedule it repeatedly while time's not up:
var runRepeatedly = function(f, secs) {
var start = Date.now();
var reschedule = function() {
var now = Date.now();
if (now - start < secs * 1000) {
setTimeout(repeat, 0)
}
}
var repeat = function() {
f();
reschedule();
};
repeat();
}
...
runRepeatedly(x, n);
Note that x should not take too long to return.

Here my solution:
<html>
<body>
<p id="demo"></p>
<button onclick="clearInterval(myVar)">Stop time</button>
<script>
var myVar = setInterval(function(){myTimer()},1000);
function myTimer() {
var d = new Date();
document.getElementById("demo").innerHTML = d.toLocaleTimeString();
}
</script>
</body>
</html>

Related

Looping a function, unexpected behaviour

Im wondering what is wrong with this for loop here. I'm trying to make a Pomodoro Study Timer, a study technique that suggests that you break down studying into 25-minute chunks that are followed by 3-5 minute breaks. here I have 2 timers that run in sequence, one after the other. When the first timer reaches zero, the second one starts. For now, i have timers set to 5 seconds and 3 seconds respectively in order to make testing quicker. It all works fine until I put the whole thing into a for loop which then brings some unexpected behaviour. I want to loop the entire function based on user input which informs the code on how many times to loop the counters(this isnt setup yet).
The timers are started by pressing a button on an html page. The button executes the pomo() function at the bottom, which contains a loop that should loop the start() function.
PS, I'm a total ultra noob so apologies if this is just terrible code, I'm really new to this :)
var time25 = 5;
var time5 = 3;
var timeElapsed25 = 0;
var timeElapsed5 = 0; // initializes time elapsed to zero
var time = document.getElementsByClassName("header"); //links to html
time[0].innerHTML = time25; // sets output to html
function convertToMin(s) {
mins = Math.floor(s / 60);
let minsStr = mins.toString();
if (minsStr.length === 1) {
mins = '0' + mins;
}
sec = s % 60;
let secStr = sec.toString();
if (secStr.length === 1) {
sec = '0' + sec;
}
return mins + ':' + sec;
}
function start() {
var timer25 = setInterval(counter25, 1000);
console.log("timer1");
function counter25() {
timeElapsed25++
time[0].innerHTML = convertToMin(time25 - timeElapsed25);
if (timeElapsed25 === time25) {
console.log("timer2")
clearInterval(timer25);
timeElapsed25 = 0;
var timer5 = setInterval(counter5, 1000);
function counter5() { //Counter For 5 minute break
timeElapsed5++;
time[0].innerHTML = convertToMin(time5 - timeElapsed5);
if (timeElapsed5 === time5) {
clearInterval(timer5);
timeElapsed5 = 0;
}
}
}
}
}
function pomo() {
for (j = 0; j < 3; j++) {
start();
}
}
You shouldn't call start() in a loop. setInterval() doesn't wait for the the countdown to complete, it returns immediately, so you're starting all 3 timers at the same time.
What you should do is call start() again when both timers complete. To put a limit on the number of repetitions, use a count parameter, and decrement it each time you call again.
var time25 = 5;
var time5 = 3;
var timeElapsed25 = 0;
var timeElapsed5 = 0; // initializes time elapsed to zero
var time = document.getElementsByClassName("header"); //links to html
time[0].innerHTML = time25; // sets output to html
function pomo() {
start(3);
}
function start(count) {
if (count == 0) { // reached the limit
return;
}
var timer25 = setInterval(counter25, 1000);
console.log("timer1");
function counter25() {
timeElapsed25++
time[0].innerHTML = convertToMin(time25 - timeElapsed25);
if (timeElapsed25 === time25) {
console.log("timer2")
clearInterval(timer25);
timeElapsed25 = 0;
var timer5 = setInterval(counter5, 1000);
function counter5() { //Counter For 5 minute break
timeElapsed5++;
time[0].innerHTML = convertToMin(time5 - timeElapsed5);
if (timeElapsed5 === time5) {
clearInterval(timer5);
timeElapsed5 = 0;
start(count - 1); // Start the next full iteration
}
}
}
}
}
function convertToMin(s) {
mins = Math.floor(s / 60);
let minsStr = mins.toString();
if (minsStr.length === 1) {
mins = '0' + mins;
}
sec = s % 60;
let secStr = sec.toString();
if (secStr.length === 1) {
sec = '0' + sec;
}
return mins + ':' + sec;
}

Waiting for a method inside an object constructor to complete before continuing

I am building a timer that counts from 25 mins to 0 and then from 5mins to 0 a certain number of times. Right now, I have a CountDownTimer object with a param of 25*60 that counts from 25 to 0. I want to start a new timer that would count from 5 to 0 once the other timer reaches 0. How do I implement this type of asynchronous code and then execute that asynchronous code X number of times?
$(document).ready(function(){
var sessionBreakTimer = new CountDownTimer(25*60);
sessionTimer.start();
if (!sessionTimer.isRunning) {
sessionBreakTimer.start();
}
);
function CountDownTimer(secs) {
var duration = secs;
var running = false;
this.start = function() {
running = true;
var startT = new Date().getTime();
var intervalId = window.setInterval(function() {
var msDelta = new Date().getTime() - startT; // milliseconds elapsed since start
var secsLeft = duration - Math.floor(msDelta / 1000);
if (secsLeft === 0) {
window.clearInterval(intervalId);
console.log("cleared");
running = false;
}
}, 1000); //update about every second
};
this.isRunning = function() {
return running;
}
}
Try utilizing Promise
var intervalId,
// current count
count = 0,
// current stop
stop = 2,
// cycles of `session`
ticks = 0,
// cycles of `session` to call
total = 2,
counter = function counter(session) {
var fn = function fn() {
// call `CountDownTimer.start()`
return new CountDownTimer(session[count]).start()
.then(function(data) {
console.log(data);
// recursively call `counter`
return counter(session)
})
}
return count < stop ? fn() : (function() {
// increment `ticks`
++ticks;
// reset `count` to `0`
count = 0;
return ticks < total
? fn()
// do stuff when `ticks` equal to `total`
: Promise.resolve({
count: count,
ticks: ticks,
total: total
})
}())
}
function CountDownTimer(secs) {
var duration = secs;
var running = false;
countdown = this;
this.start = function() {
// return `Promise` object from `CountDownTimer.start`
return new Promise(function(resolve) {
running = true;
var startT = new Date().getTime();
intervalId = window.setInterval(function() {
// milliseconds elapsed since start
var msDelta = new Date().getTime() - startT;
var secsLeft = duration - Math.floor(msDelta / 1000);
console.log(secsLeft);
if (secsLeft === 0) {
window.clearInterval(intervalId);
// increment `count`
++count;
console.log("cleared");
running = false;
resolve({
count: count,
ticks: ticks,
total: total
})
}
}, 1000); //update about every second
})
};
this.isRunning = function() {
return running;
};
}
// settings for `sessions`
// set to 60 seconds, 30 seconds for stacksnippets
var sessions = [1 * 60, 0.5 * 60];
// var sessions = [25 * 60, 5 * 60];
counter(sessions)
// do stuff when all cycles of `ticks` complete
.then(function(data) {
console.log("complete:", data)
});
You could add a callback method to your countdown and set it so it calls the proper timer when you reach 0 sec. Like this for example:
function CountDownTimer(secs) {
var self = this;
var duration = secs;
var running = false;
this.callback = function(){}; //This will allow you to define this afterwards
this.start = function() {
running = true;
var startT = new Date().getTime();
var intervalId = window.setInterval(function() {
var msDelta = new Date().getTime() - startT; // milliseconds elapsed since start
var secsLeft = duration - Math.floor(msDelta / 1000);
if (secsLeft === 0) {
window.clearInterval(intervalId);
console.log("cleared", secs);
running = false;
self.callback();//your callback is being called here
}
}, 1000); //update about every second
};
this.isRunning = function() {
return running;
}
}
And you define it like this:
$(document).ready(function(){
var sessionBreakTimer = new CountDownTimer(25*60);
var sessionTimer = new CountDownTimer(5*60);
sessionBreakTimer.callback = sessionTimer.start;//sessionTimer will be called when breaktimer is over
sessionTimer.callback = sessionBreakTimer.start;//and vice versa
sessionTimer.start();
});
http://jsfiddle.net/bw0nzw3m/1/
If you want this to be executed only a specific number of times, you'll need a variable to count every time a timer is called, and when it's over, you set your callback to a function with finish behavior or just an empty function depending on your need.

javascript Call function 10 times with 1 second between

How to call a function 10 times like
for(x=0; x<10; x++) callfunction();
but with 1 sec between each call?
function callNTimes(func, num, delay) {
if (!num) return;
func();
setTimeout(function() { callNTimes(func, num - 1, delay); }, delay);
}
callNTimes(callfunction, 10, 1000);
EDIT: The function basically says: make a call of the passed function, then after a bit, do it again 9 more times.
You can use setInterval for repeated execution with intervals and then clearInterval after 10 invocations:
callfunction();
var callCount = 1;
var repeater = setInterval(function () {
if (callCount < 10) {
callfunction();
callCount += 1;
} else {
clearInterval(repeater);
}
}, 1000);
Added: But if you don't know how long it takes your callfunction to execute and the accurate timings between invocation starting points are not important it seems it's better to use setTimeout for reasons mentioned by Paul S and those described in this article.
Another solution
for(var x=0; x<10; x++) window.setTimeout(callfunction, 1000 * x);
You can try to use setInterval and use a variable to count up to 10. Try this:
var number = 1;
function oneSecond () {
if(number <= 10) {
// execute code here..
number++;
}
};
Now use the setInterval:
setInterval(oneSecond, 1000);
Similar to Amadan's answer but with a different style of closure which means you re-use instead of creating new functions
function call(fn, /* ms */ every, /* int */ times) {
var repeater = function () {
fn();
if (--times) window.setTimeout(repeater, every);
};
repeater(); // start loop
}
// use it
var i = 0;
call(function () {console.log(++i);}, 1e3, 10); // 1e3 is 1 second
// 1 to 10 gets logged over 10 seconds
In this example, if you were to set times to either 0 or Infinity, it would run forever.
I don't know if there's a proper name, but I use a repeater:
function Repeater(callback, delay, count) {
var self = this;
this.timer = setTimeout(function() {self.run();},delay);
this.callback = callback;
this.delay = delay;
this.timesLeft = count;
this.lastCalled = new Date().getTime();
}
Repeater.prototype.run = function() {
var self = this;
this.timesLeft--;
this.callback();
this.lastCalled = new Date().getTime();
if( this.timesLeft > 0) {
this.timer = setTimeout(function() {self.run();},this.delay);
}
}
Repeater.prototype.changeDelay = function(newdelay) {
var self = this;
clearTimeout(this.timer);
this.timer = setTimeout(function() {self.run();},
newdelay-new Date().getTime()+lastcalled);
this.delay = newdelay;
}
Repeater.prototype.changeCount = function(newcount) {
var self = this;
if( this.timesLeft == 0) {
this.timer = setTimeout(function() {self.run();},this.delay);
}
this.timesLeft = newcount;
if( this.timesLeft == 0) clearTimeout(this.timer);
}
You can then use it like this:
new Repeater(callfunction, 1000, 10); // 1 second delay, 10 times
const functionCounterTimer = (callCount) => {
if (callCount < 10) {
setTimeout(() => {
++callCount
console.log("Function Call ", callCount);
functionCounterTimer(callCount);
}, 1000);
}
}
functionCounterTimer(0);
The above was my approach to a similar question.
setInterval(function(){},1000);
Calls the function for every second...
You can also use setTimeout for your thing to work.

Java script count up timer

I have a working count down timer in java script and it count down from 120 seconds to 0, now I want to change it to becomes a COUNT UP timer, try few thing still not work. could anyone help to change it to COUNT UP instead of COUNT DOWN.
Here is the code below:
<script type="text/javascript" >
var m = 0;
var s = 120;
var timer_container = document.getElementById("survey-timer");
timer_container.innerHTML = s + "." + m;
function timer() {
if (m<=0) {
m = 9;
s -= 1;
}
if(s>=0) {
m -= 1;
timer_container.innerHTML = s + "." + m;
setTimeout(timer,100);
}
}
</script>
You want to count up from 120 or from 0.. below one just count up from 0..
<script type="text/javascript" >
var m=0
var s=0
var timer_container=document.getElementById("survey-timer");
timer_container.innerHTML=s+"."+m;
function timer(){
if (m>=9){
m=-1;
s+=1;
}
if(s>=0){
m+=1;
timer_container.innerHTML=s+"."+m;
setTimeout(timer,100);
}
}
</script>
Here is working example from jsfiddle
If it were me, I would do this:
var base = new Date();
var timer_container = document.getElementById("survey-timer");
timer();
function timer() {
var now = new Date();
// elapsed time in seconds
var elapsed = (now - base) / 1000.0;
timer_container.innerHTML = elapsed.toFixed(1);
setTimeout(timer, 100);
}
<div id="survey-timer"> </div>
Because I think the technique used in the question and in rahul's answer might 'slip' if the timeout were delayed for whatever reason.

Plain JS countdown with repeat and delay

I keep running into several issues when creating a countdown script
it does not run smoothly
hard to make it repeat (closure)
hard to delay the start and to delay the repeat (closure)
Can someone please help me FIX this code which should work in my opinion but doesn't
the processing I need is
a. counter starts delay number of seconds after the page loads,
b. when counter reaches 0, the countdown RE-starts after delay number of seconds
Here is my Fiddle
Issues:
when it starts, the counter seems to wait an additional second before counting down
it does not pause
the repeat starts after the counter has continued
.
// more accurate timer - https://gist.github.com/1185904
function interval(duration, fn){
this.baseline = undefined
this.run = function(){
if(this.baseline === undefined){
this.baseline = new Date().getTime()
}
fn()
var end = new Date().getTime()
this.baseline += duration
var nextTick = duration - (end - this.baseline)
if(nextTick<0){
nextTick = 0
}
(function(i){
i.timer = setTimeout(function(){
i.run(end)
}, nextTick)
}(this))
}
this.stop = function(){
clearTimeout(this.timer)
}
}
window.onload=function() {
var cnt1 = 10;
var delay1 = 5;
var timer1 = new interval(1000, function(){
document.getElementById('out1').innerHTML=cnt1--
if (cnt1 <= 0) { // trying to reset
timer1.stop(); // does not work
cnt1 = 10;
setTimeout(function() { timer1.run()},delay1*1000)
}
})
setTimeout(function() { timer1.run()},delay1*1000)
}
I've rewritten your code to produce the desired results. Your previous code was very inefficient. See my script comments for usage.
Fiddle: http://jsfiddle.net/RVBDQ/1/
/*
#name timer
#param number startFrom Starts counting down from this number
#param number delay Seconds to wait before repeating the counter
#param number intervalDelay Milliseconds between countdown
#param number runTimes Optional; Limit of counting. The function stops when it has run <runTimes> times. Default 1 (=one countdown)
#param Boolean noFirstRun Optional; If false, the counter starts off immediately. Default false
*/
function timer(startFrom, delay, intervalDelay, runTimes, notFirstRun){
if(typeof runTimes == "undefined") runTimes = 1;
if(runTimes-- < 0) return;
setTimeout(function(){
var ctn = startFrom;
var timer1 = window.setInterval(function(){
document.getElementById('out1').innerHTML = ctn--;
if(ctn <= 0){
clearInterval(timer1);
timer(startFrom, delay, intervalDelay, runTimes, true);
}
}, intervalDelay);
}, notFirstRun?delay*1000:0);
}
window.onload=function() {
timer(10, 5, 1000, 2);
//Runs two times, starts counting from 10 to 1, delays 5 seconds between counters.
}
Object exposing start([delay]) and stop().
http://jsfiddle.net/RVBDQ/3/
function interval(duration, fn, delay){
this.timer = null;
this.duration = duration;
this.fn = fn;
this.start(delay);
}
interval.prototype.start = function(delay){
if (this.timer) {return;}
var self=this;
this.timer = setTimeout(function(){ self.run(); }, delay||0);
};
interval.prototype.run = function(called){
var self = this,
nextTick = called ? this.duration - (new Date - called) : 0;
this.timer = setTimeout(function(){
self.fn();
self.run(new Date);
}, nextTick<0 ? 0 : nextTick);
};
interval.prototype.stop = function(){
clearTimeout(this.timer);
this.timer = null;
};
window.onload = function() {
var cnt1 = 10;
var delay1 = 5;
window.timer1 = new interval(1000, function(){
document.getElementById('out1').innerHTML=cnt1;
cnt1 = cnt1 === 1 ? 10 : cnt1-1;
}, delay1*1000);
};

Categories