Add duration to JS setTimeout after the timer is running - javascript

I'm trying to figure out a way to emulate AS3's Timer class.
If you're not familiar, one of the cool things you can do is add duration to the timer even if it's already running. This functionality has a lot of very nice uses.
Anyone have any thoughts on doing this in js?

I'm not familiar with this class, but you can easily create something similar in JavaScript:
function Timer(callback, time) {
this.setTimeout(callback, time);
}
Timer.prototype.setTimeout = function(callback, time) {
var self = this;
if(this.timer) {
clearTimeout(this.timer);
}
this.finished = false;
this.callback = callback;
this.time = time;
this.timer = setTimeout(function() {
self.finished = true;
callback();
}, time);
this.start = Date.now();
}
Timer.prototype.add = function(time) {
if(!this.finished) {
// add time to time left
time = this.time - (Date.now() - this.start) + time;
this.setTimeout(this.callback, time);
}
}
Usage:
var timer = new Timer(function() { // init timer with 5 seconds
alert('foo');
}, 5000);
timer.add(2000); // add two seconds

Clear the timeout, then set a new timeout to the new desired end time.

Wrap the function with another one, and when the timer runs out, test to see if an extra time variable has been set. If it has, start again with the new time, otherwise execute the function.
A quickly hacked together script might look like:
function test() {
tim = new timer(function () { alert('hello'); }, 5000);
}
function extend() {
if (tim) { tim.addTime(5000); }
}
function timer(func, time) {
var self = this,
execute = function () {
self.execute()
};
this.func = func;
this.extraTime = 0;
setTimeout(execute, time);
};
timer.prototype.execute = function () {
var self = this,
execute = function () {
self.execute()
};
if (this.extraTime) {
setTimeout(execute, this.extraTime);
this.extraTime = 0;
} else {
this.func();
}
};
timer.prototype.addTime = function (time) {
this.extraTime += time;
}
<input type="button" value="Start" onclick="test()">
<input type="button" value="Extend" onclick="extend()">

There you go hope it helps :) just call setInterval with the time you want to have.
Edit: added stop and start in case you want to stop your loop :p
function Timer(defaultInterval, callback){
var interval = defaultInterval;
var running = true;
function loop(){
callback();
if(running){
setTimeout(function(){
loop();
}, interval);
}
}
loop();
return {
setInterval: function(newInterval){
interval = newInterval;
},
stop: function(){
running = false;
},
start: function(){
if(running===false){
running = true;
loop();
}
},
add: function(milliToAdd){
interval += milliToAdd*1;
}
}
}
var myTimer = Timer(250, function() { process code here });
myTimer.setInterval(1000); // sets interval to 1 second
myTimer.stop(); // stops the function
myTimer.start(); // re-starts the loop;

function Timer(func, delay) {
var done = false;
var callback = function() {
done = true;
return func();
};
var startTime = Date.now();
var timeout = setTimeout(callback, delay);
this.add = function(ms) {
if (!done) {
this.cancel();
delay = delay - (Date.now() - startTime) + ms;
timeout = setTimeout(callback, delay);
}
};
this.cancel = function() {
clearTimeout(timeout);
};
this.immediately = function() {
if (!done) {
this.cancel();
callback();
}
};
};
quick test in the console
start = Date.now();
t = new Timer(function() { console.log(Date.now() - start); }, 1000);
t.add(200);
start = Date.now();
t = new Timer(function() { console.log(Date.now() - start); }, 1000000);
t.immediately();
t.immediately();
you can add negative times too.
start = Date.now();
t = new Timer(function() { console.log(Date.now() - start); }, 1000);
t.add(-200);

Here's my shot. It keeps track of when the timer was set, and adds the difference to the specified time when you add time.
var Timer = {
set: function(p_function, p_time)
{
var d = new Date();
this.timeStarted = d.getTime();
this.func = p_function;
this.timeout = setTimeout(p_function, p_time);
console.log('timer started at ' + (this.timeStarted / 1000) + ' seconds');
},
add: function(p_time)
{
var d = new Date(),
diff = d.getTime() - this.timeStarted,
newTime = diff + p_time;
if (this.timeout)
{
clearTimeout(this.timeout);
}
this.timeout = setTimeout(this.func, newTime);
this.timeStarted = d.getTime();
}
};
var myTimer = Object.create(Timer);
myTimer.set(function() {
var d = new Date();
console.log('Timer fired at ' + (d.getTime() / 1000) + ' seconds');
}, 10000);
setTimeout(function () {
myTimer.add(5000);
}, 5000);
Here's a jsFiddle
Please note that due to overhead of calculation and function calls, this may be a couple milliseconds off.

I decided to throw my little rubber ducky into the pool.
var setTimeout2 = function(callback, delay) {
this.complete = false;
this.callback = callback;
this.delay = delay;
this.timeout = false;
this.dotimeout = function() {
this.timeout = setTimeout(function() {
this.complete = true;
this.callback.call();
}, this.delay);
};
this.start = Date.now();
this.add = function(delay) {
if (!this.complete) {
this.delay = this.delay - (Date.now() - this.start) + delay;
clearTimeout(this.timeout);
this.dotimeout.call();
}
};
return this;
};
usage
var start = Date.now();
var to = setTimeout2(function() {
document.write(Date.now() - start);
}, 3000);
to.add(3000);
similar to this approach but a little more compact / no proto

Related

How to use setTimeout without using setTimeout function

Is there a way to use setTimeout without using setTimeout inbuilt function?
I don't want to use setInterval or clearInterval either or window.use. I have gone through multiple blogs, but all those use window, setInterval or clearInterval.
For example, the below code works, but I dont want to have window.
const setTimeouts = [];
function customSetTimeout(cb, interval) {
const now = window.performance.now();
const index = setTimeouts.length;
setTimeouts[index] = () => {
cb();
};
setTimeouts[index].active = true;
const handleMessage = (evt) => {
if (evt.data === index) {
if (window.performance.now() - now >= interval) {
window.removeEventListener('message', handleMessage);
if (setTimeouts[index].active) {
setTimeouts[index]();
}
} else {
window.postMessage(index, '*');
}
}
};
window.addEventListener('message', handleMessage);
window.postMessage(index, '*');
return index;
}
const setIntervals = [];
function customSetInterval(cb, interval) {
const intervalId = setIntervals.length;
setIntervals[intervalId] = function () {
if (setIntervals[intervalId].active) {
cb();
customSetTimeout(setIntervals[intervalId], interval);
}
};
setIntervals[intervalId].active = true;
customSetTimeout(setIntervals[intervalId], interval);
return intervalId;
}
function customClearInterval(intervalId) {
if (setIntervals[intervalId]) {
setIntervals[intervalId].active = false;
}
}
console.log("1");
customSetTimeout(function() {
console.log('3s');
}, 3000);
console.log("2");
=======================================
Alternate solution:
But here, again i dont want to use clearInterval and setInterval
var setMyTimeOut = function(foo,timeOut){
console.log('inside time out');
var timer;
var currentTime = new Date().getTime();
var blah=()=>{
if (new Date().getTime() >= currentTime + timeOut) {
console.log('clear interval if');
clearInterval(timer);
foo()
}
console.log('clear interval else');
}
timer= setInterval(blah, 100);
}
console.log("1");
setMyTimeOut(function() {
console.log('3s');
}, 3000);
console.log("2");
Is there way to achieve the same but without the use setInterval and clearInterval?
I use here the requestAnimationFrame with performance.now().
Its not super exact (well setTimeout neither), but it do the work.
function sleep(delay, cb) {
function check(time, delay) {
if(time >= delay) {
cb("done");
return;
}
time = performance.now();
requestAnimationFrame(check.bind(null, time,delay))
}
check(performance.now(), delay + performance.now());
}
sleep(4000, ()=> {
console.log("sleep done");
})
console.log("i do not block the main thread");
You can use a while loop which checks a set time against the current time:
const startTime = new Date().getTime() + 3000;
let currentTime = new Date().getTime();
function customTimeout() {
while (startTime > currentTime) {
currentTime = new Date().getTime();
}
return console.log('3 Seconds')
};
customTimeout();

How to decrement given time

I am getting an output of 00:20:00 which is correct but my problem now is its not decrementing even when I have subtracted it am i missing something?
$duration=0;
$startime=date('Y-m-d H:i:s');
$end_time=$end_time=date('Y-m-d H:i:s',
strtotime('+'.$duration.'minutes',strtotime($startime)));
$timefirst=strtotime($startime);
$timesecond=strtotime($end_time);
$differenceinseconds=$timesecond-$timefirst;
echo gmdate("H:i:s", $differenceinseconds);
my script
<div id='response'></div>
<script type="text/javascript">
setInterval(function(){
var xmlhttp=new XMLHttpRequest();
xmlhttp.open("GET",'responseTime.php',false);
xmlhttp.send(null);
document.getElementById('response').innerHTML=xmlhttp.responseText;
},1000);
</script>
As RiggsFolly mentioned why waste servers time running a timer.
Here is what you can do in javascript,
<div id="stopwatch"></div>
<script>
var Stopwatch = function (elem, target, options) {
var timer = createTimer(),
offset,
clock,
interval;
// default options
options = options || {};
options.delay = options.delay || 1;
// append elements
elem.appendChild(timer);
// initialize
reset();
// private functions
function createTimer() {
var interval = 20 ; // 20 seconds
var element = document.createElement("progress");
element.setAttribute("max",interval);
return element;
}
function start() {
if (!interval) {
offset = Date.now();
interval = setInterval(update, options.delay);
}
}
function stop() {
if (interval) {
clearInterval(interval);
interval = null;
}
}
function reset() {
clock = 0;
render();
}
function update() {
clock += delta();
render();
}
function render() {
timer.value = parseInt(clock / 1000);
if(timer.value==interval){
// This is the point where timer ends, put your further code in here.
}
}
function delta() {
var now = Date.now(),
d = now - offset;
offset = now;
return d;
}
// public API
this.start = start;
this.stop = stop;
this.reset = reset;
};
var elem = document.getElementById("stopwatch");
var timer = new Stopwatch(elem, {delay: 10});
timer.start();
</script>

How to Pause the timer on window blur and resume the timer on window focus event?

Thanks for seeing my question.
I am using wp-pro-quiz plugin for quiz. I want to know that how can I pause the timer if the window is not in focus or is blur and resume it when it is back to focus.?
My code:
I get reset when it get focused
var timelimit = (function () {
var _counter = config.timelimit;
var _intervalId = 0;
var instance = {};
instance.stop = function () {
if (_counter) {
window.clearInterval(_intervalId);
globalElements.timelimit.hide();
}
};
instance.start = function () {
var x;
var beforeTime;
if (!_counter)
return;
var $timeText = globalElements.timelimit.find('span').text(plugin.methode.parseTime(_counter));
var $timeDiv = globalElements.timelimit.find('.wpProQuiz_progress');
globalElements.timelimit.show();
$.winFocus(function (event) {
console.log("Blur\t\t", event);
},
function (event) {
console.log("Focus\t\t", event);
x = _counter * 1000;
beforeTime = +new Date();
});
_intervalId = window.setInterval(function () {
var diff = (+new Date() - beforeTime);
var elapsedTime = x - diff;
if (diff >= 500) {
$timeText.text(plugin.methode.parseTime(Math.ceil(elapsedTime / 1000)));
}
$timeDiv.css('width', (elapsedTime / x * 100) + '%');
if (elapsedTime <= 0) {
instance.stop();
plugin.methode.finishQuiz(true);
}
}, 16);
};
return instance;
})();
Use this wrapper function to pause, resume your timeout.
var Timer;
Timer = function(callback, delay) {
var remaining, start, timerId;
timerId = void 0;
start = void 0;
remaining = delay;
this.pause = function() {
window.clearTimeout(timerId);
remaining -= new Date - start;
};
this.resume = function() {
start = new Date;
window.clearTimeout(timerId);
timerId = window.setTimeout(callback, remaining);
};
this.resume();
};
Intialize it like this, timer = new Timer("callback_function_here", 45000)
In this case total time is 45 seconds for the callback and upon event triggers(blur or focus in your case) it will pause or resume the timer accordingly.
timer.pause() //pause the timer
timer.resume() //resume the timer
P.S - Use this function as per the logic of your code. You will have to make the timer calls accordingly in your code
I did it this way:
var time0 ; var setTimeout_Int; var focused = true; var resume_Fun ;
var addTime =0; var addTimeDiff =0;
window.onfocus = function() {
focused = true;
var d = new Date();
addTimeDiff = addTimeDiff +( d.getTime() - addTime );
resume_Fun();
};
window.onblur = function()
{
focused = false;
};
function init()
{
var d = new Date();
time0 = d.getTime();
setTimeout_Int = setTimeout(update, 1000 )
}
function update()
{
clearTimeout(setTimeout_Int);
var d = new Date();
if(focused)
{
if(d.getTime() -(time0+addTimeDiff) < 20000)
{
setTimeout_Int= setTimeout(update, 1000 )
}
}
else
{
addTime = d.getTime();
resume_Fun = update;
}
}
init();

Stopping a Javascript setInterval that is delayed by a setTimeout

I'm having issue with this jsfiddle snippet:
http://jsfiddle.net/y45jN/7/
var mainFunction = function() {
this.text;
this.repeater;
}
var repeatEvery = function(func, interval) {
var now = new Date();
var delay = interval - now % interval;
function start() {
var intervalID = setInterval(func, interval);
func(intervalID);
}
setTimeout(start, delay);
};
mainFunction.prototype.start = function(printText) {
this.text = printText;
var self = this;
var func = function(intervalID) {
if(intervalID){
this.repeater = intervalID;
}
document.getElementById('test').innerHTML += this.text + '<br/>';
};
repeatEvery(_.bind(func, this),1000);
}
mainFunction.prototype.stop = function() {
clearInterval(this.repeater);
}
var test = new mainFunction();
test.start('hello');
setTimeout(test.stop,10000);
My goal is to call the stop function and stop the Interval that has been set by the start function.
You need to do
setTimeout(function(){ test.stop()}, 10000)
or
setTimeout(test.stop.bind(test), 10000); //Bind method is not available in IE8 though
instead of
setTimeout(test.stop, 10000);
The reason for this is that Javascript loses track of the "this" when you pass a callback to a function.

Repeating setTimeout

I am trying to repeat setTimeout every 10 seconds. I know that setTimeout by default only waits and then performs an action one time. How can I repeat the process?
setTimeout(function() {
setTimeout(function() {
console.log("10 seconds");
}, 10000);
}, 10000);
Maybe you should use setInterval()
setInterval() is probably what you're looking for, but if you want to do get the same effect with setTimeout():
function doSomething() {
console.log("10 seconds");
setTimeout(doSomething, 10000);
}
setTimeout(doSomething, 10000);
Or if you don't want to declare a separate function and want to stick with a function expression you need to make it a named function expression:
setTimeout(function doSomething() {
console.log("10 seconds");
setTimeout(doSomething, 10000);
}, 10000);
(Or use arguments.callee if you don't mind using deprecated language features.)
according to me setInterval() is the best way in your case.
here is some code :
setInterval(function() {
//your code
}, 10000);
// you can change your delay by changing this value "10000".
Unlike the answers provided by #nnnnnn and #uzyn I discourage you from making use of setInterval for reasons elaborated in the following answer. Instead make use of the following Delta Timing script:
function DeltaTimer(render, interval) {
var timeout;
var lastTime;
this.start = start;
this.stop = stop;
function start() {
timeout = setTimeout(loop, 0);
lastTime = + new Date;
return lastTime;
}
function stop() {
clearTimeout(timeout);
return lastTime;
}
function loop() {
var thisTime = + new Date;
var deltaTime = thisTime - lastTime;
var delay = Math.max(interval - deltaTime, 0);
timeout = setTimeout(loop, delay);
lastTime = thisTime + delay;
render(thisTime);
}
}
The above script runs the given render function as close as possible to the specified interval, and to answer your question it makes use of setTimeout to repeat a process. In your case you may do something as follows:
var timer = new DeltaTimer(function (time) {
console.log("10 seconds");
}, 10000);
var start = timer.start();
const myFunction = () => {
setTimeout(() => {
document.getElementById('demo').innerHTML = Date();
myFunction();
}, 10000);
}
Easiest, but not efficient way!
Here is a function using setTimeout that tried to call itself as close as it can to a regular interval. If you watch the output, you can see the time drifting and being reset.
<script type="text/javascript">
function Timer(fn, interval) {
this.fn = fn;
this.interval = interval;
}
Timer.prototype.run = function() {
var timer = this;
var timeDiff = this.interval;
var now = new Date(); // Date.now is not supported by IE 8
var newInterval;
// Only run if all is good
if (typeof timer.interval != 'undefined' && timer.fn) {
// Don't do this on the first run
if (timer.lastTime) {
timeDiff = now - timer.lastTime;
}
timer.lastTime = now;
// Adjust the interval
newInterval = 2 * timer.interval - timeDiff;
// Do it
timer.fn();
// Call function again, setting its this correctly
timer.timeout = setTimeout(function(){timer.run()}, newInterval);
}
}
var t = new Timer(function() {
var d = new Date();
document.getElementById('msg').innerHTML = d + ' : ' + d.getMilliseconds();
}, 1000);
window.onload = function() {
t.run();
};
</script>
<span id="msg"></span>
Using jQuery, this is what you could do:
function updatePage() {
var interval = setTimeout(updatePage, 10000); // 10' Seconds
$('a[href]').click(function() {
$(this).data('clicked', true);
clearInterval(interval); // Clears Upon Clicking any href Link
console.log('Interval Cleared!');
});
// REPLACE 'YOUR_FUNCTION_NAME' function you would like to execute
setTimeout(YOUR_FUNCTION_NAME, 500);
} // Function updatePage close syntax
updatePage(); // call the function again.

Categories

Resources