How to make a countdown timer function reusable - javascript

I have a countdown function like the following:
data(){
return {
timer: null
}
}
methods: {
countdown: function(time){
const TIME_COUNT = time;
if (!this.timer) {
this.count = TIME_COUNT;
this.timer = setInterval(() => {
if (this.count > 0 && this.count <= TIME_COUNT) {
this.count--;
}
else{
clearInterval(this.timer);
this.timer = null;
}
}, 1000);
}
I want to call the countdown function with different parameters like countdown(10) or countdown(60) so that every time I call this function it starts counting from the time I want. If I call the countdown method it will count to 0 before the second countdown works. What should I do to make it reusable?

This should let you instantiate multiple countdown instance functions.
const methods = {
countdown: (time) => {
let timeRemaining = time;
let timer;
timer = setInterval(() => {
if (timeRemaining > 0) {
timeRemaining--;
} else {
clearInterval(timer);
}
}, 1000)
}
}

Related

How to update setInterval data every x seconds without affecting inside setInterval?

How can i update ranType every 30 seconds.
since ranType is random if ranType === 'works' how to add interval to update inside data every 10 seconds.
This is what i tried:
setInterval(() => {
let type = ['works', 'testing'];
let ranType = type[Math.floor(Math.random() * type.length)];
if (ranType === 'works') {
setInterval(async () => {
console.log(`Okay Working ${RANDOM DATA}`);
}, 10000);
} else {
setInterval(async () => {
console.log(`Testing also working ${RANDOM DATA}`);
}, 10000); // But RANDOM DATA should update every 10 seconds - I have RANDON data
}
}, 30000); // ranType should update every 30 seconds
expected output:
After 30 seconds
if ranType is 'works'
it should repeat console with random data every 10 seconds
Again after 30 seconds it (ranType) should change to testing
if ranType is 'testing'
it should repeat console with other random data every 10 seconds
Other issues is its keep repeting 3-4 times every 10 seconds.
Ok, I think this is what you want, please let me know if is not the expected result. Every 30 seconds the outer setInterval clears the last intervalId and creates a new one.
let intervalId;
setInterval(() => {
let type = ["works", "testing"];
let ranType = type[Math.floor(Math.random() * type.length)];
console.log("new cycle of interval of 30 seconds");
clearInterval(intervalId);
setTimeout(() => {
if (ranType === "works") {
intervalId = setInterval(async () => {
console.log(`Okay Working`);
}, 10000);
} else {
intervalId = setInterval(async () => {
console.log(`Testing also working`);
}, 10000);
}
});
}, 30000);
EDIT
created a new version which might be clearer
const setIntervalXTimes = (callback, delay, repetitions) => {
let count = 0;
let intervalID = setInterval(() => {
if (count === repetitions) {
clearInterval(intervalID);
} else {
callback();
}
count++;
}, delay);
};
setInterval(() => {
let type = ["works", "testing"];
let ranType = type[Math.floor(Math.random() * type.length)];
if (ranType === "works") {
setIntervalXTimes(() => console.log(`Okay Working`), 1000, 3);
} else {
setIntervalXTimes(() => console.log(`Testing also working`), 1000, 3);
}
}, 3000);
const ranType_reset_period = 30000;
const works_reset_period = 10000;
const testing_reset_period = 10000;
const random_data_reset_period = 10000;
let works_interval = -1;
let testing_interval = -1;
let RANDOM_DATA = "RANDOM_DATA_DEFAULT";
function reset_random_data() {
let sample_random_data = ['RANDOM_DATA_1', 'RANDOM_DATA_2', 'RANDOM_DATA_3', 'RANDOM_DATA_4'];
RANDOM_DATA = sample_random_data[Math.floor(Math.random() * sample_random_data.length)];
console.log('RANDOM_DATA', 'RESET', RANDOM_DATA);
}
function get_random_ranType() {
let type = ['works', 'testing'];
return type[Math.floor(Math.random() * type.length)];
}
function reset_works_interval() {
console.log(`Okay Working ${RANDOM_DATA}`);
}
function reset_testing_interval() {
console.log(`Testing also working ${RANDOM_DATA}`);
}
function reset_rantype() {
clearInterval(works_interval);
clearInterval(testing_interval);
if (get_random_ranType() === 'works') {
works_interval = setInterval(reset_works_interval, works_reset_period);
} else {
testing_interval = setInterval(reset_testing_interval, testing_reset_period); // But RANDOM DATA should update every 10 seconds - I have RANDON data
}
}
setInterval(reset_random_data, random_data_reset_period);
setInterval(reset_rantype, ranType_reset_period);
Illustration
const ranType_reset_period = 30000;
const works_reset_period = 10000;
const testing_reset_period = 10000;
const random_data_reset_period = 10000;
let works_interval = -1;
let testing_interval = -1;
let RANDOM_DATA = "RANDOM_DATA_DEFAULT";
function reset_random_data() {
let sample_random_data = ['RANDOM_DATA_1', 'RANDOM_DATA_2', 'RANDOM_DATA_3', 'RANDOM_DATA_4'];
RANDOM_DATA = sample_random_data[Math.floor(Math.random() * sample_random_data.length)];
console.log('RANDOM_DATA', 'RESET', RANDOM_DATA);
}
function get_random_ranType() {
let type = ['works', 'testing'];
return type[Math.floor(Math.random() * type.length)];
}
function reset_works_interval() {
console.log(`Okay Working ${RANDOM_DATA}`);
}
function reset_testing_interval() {
console.log(`Testing also working ${RANDOM_DATA}`);
}
function reset_rantype() {
clearInterval(works_interval);
clearInterval(testing_interval);
if (get_random_ranType() === 'works') {
works_interval = setInterval(reset_works_interval, works_reset_period);
} else {
testing_interval = setInterval(reset_testing_interval, testing_reset_period);
}
}
setInterval(reset_random_data, random_data_reset_period); // But RANDOM DATA should update every 10 seconds - I have RANDON data
setInterval(reset_rantype, ranType_reset_period);

How i can listen/change my state with setIntreval?

I need show my timer in react component, he working in function but i can't show his in html because my state very bad working.
const date = { // timer context
hours: 0,
minutes: 0,
seconds: 0,
isActive: false,
start: function() {
this.isActive = true;
return this
},
stop: function() {
this.isActive = false;
return this
}
}
function timer() { //timer function
if(this.isActive) {
if(this.seconds < 60) date.seconds += 1;
else {
this.seconds = 0;
if(this.minutes < 60) date.minutes += 1;
else {
this.minutes = 0;
this.hours += 1;
}
}
}
return this
}
const myTimer = timer.bind(date);
const [timerState, setTimerState] = useState({}); // myState
let interval;
useEffect(() => {
if(interval) clearInterval(interval);
interval = setInterval(() => {
if(clients.length > 1) {
setTimerState(myTimer().start()); // state changed
} else {
setTimerState(myTimer().stop());
}
console.log(timerState);
}, 1000);
}, [clients, timerState /* waiting update states */]); // but i can't wait only clients otherwise i get empty object {} if remove timerState from wait states
I need withdraw timer state in html component return ({timerState})
Tell me please what i need. Thanks.

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();

Can i call a action in every 20 second inside a timer which is always running in every second

I need to print a console in every 20 second(technically i will call a action in reactjs) inside a interval which is running in every second.
this is a dummy code not functioning properly.
var intervalDuration = 200;
var hitOnEvery = 20;
setInterval(() => {
interValDuration -= 1;
if (interValDuration >= 0) {
setTimeout(()=>{
console.log(interValDuration , 'Hit on every' + hitOnEvery + 'second')
},hitOnEvery);
}
console.log('This will print every '+intervalDuration +'count in a place')
}, 1000);
can someone correct and help me.
You can do it like this:
var interValDuration = 200;
var hitOnEvery = 20;
setInterval(() => {
interValDuration -= 1;
if (interValDuration % hitOnEvery == 0) {
console.log(interValDuration , 'Hit on every' + hitOnEvery + 'second')
}
console.log('This will print every '+interValDuration +'count in a place')
}, 1000);
Basically check if interValDuration divided by hitOnEvery has 0 leftover after division, meaning every 20sec perform action
Here is the closure function, for the generic usage
const timer = (() => {
let timer;
let seconds = 1;
return (func, hitAtTime) => {
let stopTimer = () => {
console.log(timer);
window.clearInterval(timer);
};
const startTimer = () => {
timer = window.setInterval(() => {
console.log("i run every second");
seconds++;
if (seconds % hitAtTime === 0) {
func();
}
}, 1000);
};
return {
stopTimer: stopTimer,
startTimer: startTimer,
};
};
})();
timer(() => console.log("i run every 10 seconds"), 10).startTimer();

Clear interval inside object method

This code is part of a game where the user has a certain amount of time to input an answer.
I want to be able to clear the interval from outside of the object if the user decides to submit an answer before the allotted time has elapsed.
I have tried returning the interval with an ID so that I can call it later and whilst this does allow me to clear it from outside the outside the object, it means that the code inside the interval function is never run.
const clock = {
timer: 30,
countdown() {
let interval = setInterval(function () {
selectors.timerDisplay.textContent = clock.timer
clock.timer--
if (clock.timer < 0) {
clearInterval(interval)
selectors.wordSubmit.click();
}
}, 1000)
},
}
I appreciate I may have simply set myself up badly to clear this interval, therefore any suggestions on how I could improve it would be appreciated.
Thanks in advance.
You can use Arrow functions to leverage the context of this from your object clock
Add a method i.e clear.
Use this context to reference your inner attributes.
const clock = {
timer: 3,
interval: 0,
reset() {
this.timer = 3;
this.interval = 0;
},
clear() {
clearInterval(this.interval);
this.reset();
},
countdown() {
this.interval = setInterval(() => {
//selectors.timerDisplay.textContent = clock.timer
this.timer--;
console.log(this.timer)
if (this.timer < 0) {
clearInterval(this.interval)
//selectors.wordSubmit.click();
}
}, 1000);
},
}
clock.countdown();
setTimeout(function() {
clock.clear();
}, 1500)
See? the interval function ends after 1.5secs
You can expose a method to clear the interval
const selectors = document.querySelector('div');
const clearTimer = document.querySelector('button');
const clock = {
timer: 5,
// Initiate the interval
int: null,
// This exposes a way to clear the interval outside of the object
clearTimer() {
clearInterval(this.int);
},
countdown() {
// This is where you define this.int
this.int = setInterval(() => {
//selectors.timerDisplay.textContent = clock.timer
selectors.innerText = clock.timer.toString();
clock.timer--
console.log(clock.timer);
if (clock.timer < 0) {
this.clearTimer();
//selectors.wordSubmit.click();
}
}, 1000)
},
}
clock.countdown();
clearTimer.addEventListener('click', () => {
clock.clearTimer();
})
<div>clock.timer</div>
<button>clear timer</button>
As has been suggested in the comments, simply return the interval so it can be stopped later. For example
countdown() {
let interval = setInterval(function () {
selectors.timerDisplay.textContent = clock.timer
clock.timer--
if (clock.timer < 0) {
clearInterval(interval)
selectors.wordSubmit.click();
}
}, 1000)
return interval // added this line
},
Then, consumers can cancel the interval when they want
const interval = clock.countdown()
// and later...
clearInterval(interval)

Categories

Resources