Function only executes once in for loop - javascript

I have a function that starts a timer that can be paused. Now I want several timers to run after each other, for this I decided to use a for loop.
However, when I call the function inside the loop, even though the loop goes n (5 in this case) times, the function only executes once, while the console.log executes 5 times as intended. What am I doing wrong here?
var timer = null;
const resetTimer = () => {
clearInterval(timer);
timer = null;
}
function trigger (startTime, endTime, sets){
for (let i = 0; i < sets; i++){
myTimer(startTime, endTime, sets);
console.log("1")
}
}
function myTimer (startTime, endTime, sets){
if (!timer) {
timer = setInterval(function() {
display.innerHTML = hhmmss(++startTime);
if (startTime >= endTime) {
resetTimer();
}
}, 1000);
}
}

Your function is called every time, but in all of the calls after the first one, if (!timer) is false, so it doesn't do anything.
If you want multiple timers, you'll need multiple places to store the timer handle. For instance, in a local within myTimer:
// No global `timer`
// Accept the timer to clear (no real reason for this function if all it does is `clearInterval`)
const resetTimer = (timer) => {
clearInterval(timer);
};
function trigger (startTime, endTime, sets){
for (let i = 0; i < sets; i++){
myTimer(startTime, endTime, sets);
}
}
function myTimer(startTime, endTime, sets) {
// There's a different `timer` for each call to `myTimer`
const timer = setInterval(function() {
display.innerHTML = hhmmss(++startTime);
if (startTime >= endTime) {
// Pass this timer's `timer` to `resetTimer`
resetTimer(timer);
}
}, 1000);
}

You've used if (!timer) { so on the first iteration it will assign something to timer and after that nothing inside that if will execute again.

Related

How can I postpone setInterval if a condition is met?

This is my script:
var find = setInterval(function() {
if (document.getElementsByClassName('RDlrG Inn9w iWO5td')[0]) {
if (document.getElementsByClassName('w1OTme')[0]) {
window.open(document.getElementsByClassName('w1OTme')[0].href);
//here I call the setTimeout function for my SetInterval
}
}
}, 2000);
This is a Tampermonkey script I am developing for Google Calendar.
I want to set a timeout function on my find function aka setInterval function so it doesn't spam the window.open function.
In short:
Is there a way I could set a Timeout function on setInterval function which is called from my setInterval function?
If yes, how so?
You can't pause the interval of a setInterval, but you can stop it and start it again after some time.
let find = null;
function intervalFunc() {
if (condition) {
// Do some operations which should not be repeated for the next 30 seconds
// Clear current interval
clearInterval(find);
// Schedule to start the setInterval after 30 seconds.
setTimeout(function() {
find = setInterval(intervalFunc, 2000);
}, 30000 - 2000);
// ^
// Subtracting the interval dalay to cancel out the delay for the first invocation.
// (Because the first invocation will also wait for 2 seconds, so the pause would be 32 seconds instead of 30)
}
}
// Start the initial setInterval
find = setInterval(intervalFunc, 2000);
Here is a working example:
let count = 0;
const intervalDelay = 200;
const pauseDelay = 3000;
let find = null;
function intervalFunc() {
count++;
console.log('check', count);
if (count >= 5) {
count = 0;
console.log('Pausing for ' + (pauseDelay / 1000) + ' seconds');
clearInterval(find);
setTimeout(function() {
find = setInterval(intervalFunc, intervalDelay);
}, pauseDelay - intervalDelay);
}
}
find = setInterval(intervalFunc, intervalDelay);

need help fixing a countdown clock with javascript

I am trying to create a countdown clock and have hit a bit of a snag. It is displaying the final number, the final result of the for loop, which I don't want. My goal is to have to for loop fire my .setTimeout every time it loops. I would appreciate any help.
const countdownClock = (ranNum) => {
const startingNum = ranNum * 50;
for(let i = startingNum; i > 0; i--) {
setTimeout(() => countdownSpan.textContent = [i], 1000);
}
}
That's because of the setTimeout is waiting for 1s to execute and until then the loop is completed even before your first setTimeout triggers and when your first timeout is triggered the value of i is updated and is now the last number of the loop. You can handle it with the promises and async/await.
const countdownClock = async (ranNum) => {
const startingNum = ranNum * 50;
for(let i = startingNum; i > 0; i--) {
await new Promise(resolve => {
setTimeout(() => {
countdownSpan.textContent = [i];
resolve()
}, 1000)
});
}
}
Hope it helps!
Timer functions won't fire until after the current function is complete. This is why your for loop runs to completion before the timer function runs. In order to see the timer tick away, you shouldn't use a loop at all because the timer will create the looping functionality. You only need either a setInterval() or a setTimeout() that is recursive.
const element = document.getElementById("countdown");
let startingNum = parseInt(Math.random() * 50, 10);
let timer = null;
function counter(){
// Clear any running timer to prevent multiple
// timers from stacking up in the event queue
clearTimeout(timer);
startingNum--; // Decrease the counter
// If the count is greater than 0
if(startingNum >-1){
element.textContent = startingNum;
// Set a new timer up to call this function
timer = setTimeout(counter, 1000);
}
}
// Start the process off
timer = setTimeout(counter, 1000);
<div id="countdown"></div>

JS : how to write a function witch accept another function as parameter and return a function

I ve to write a function myFunction that accepts another function (myCallbackFunction) as parameter .
myFunction would return a resulted function myResultFunction() which calls the callback
myResultFunction is called every 100ms
the callback function ; myCallbackFunction should be called at most once every 300 ms
it's something like this :
function myFunction(paramFunction){
return setInterval( myResultFunction(paramFunction); , 100);
// paramFunction is the callback taht should be called at once 300ms
}
function myResultFunction(paramfunction){
return setInterval( paramfunction(); , 300);
}
myFunction(myCallbackFunction);
i need to adapt to have this behaviour :
myFunction is called initially , so myCallbackFunction has not yet been called in the last 300 ms
at t= 0ms : myResultFunction();
at t=100ms : myResultFunction();
at t=200ms : myResultFunction();
at t=300 ms : myCallbackFunction() ;
this behaviour should loop indefinetly so that the first time the callback mybe called
Suggestions to write myFunction , myCallbackFunction and myResultFunction ??**
This is when you actually take advantage of iterators and generators, available in ES6. Basically, myFunction will be the iterator that will iterate on indefinitely in a while(true) loop. For each iteration, you increment the iteration by 1. Every 4thiteration will return the result of myCallbackFunction(), otherwise it will return the result of myResultFunction().
Once you instantiate your iterator, you can then call the .next() method on it at the desired interval: in your case, you want it to step every 100ms. I have slightly adjusted the proof-of-concept below to step every 1000ms so that you can actually see what is going on:
function* myFunction(callback) {
let count = 1;
while (true) {
let output;
if (count % 4 === 0)
output = callback();
else
output = myResultFunction();
count++;
yield output;
}
}
function myResultFunction() {
return 'myResultFunction(): called every count';
}
function myCallbackFunction() {
return 'myCallbackFunction(): called at every fourth count';
}
var iteratorFunction = myFunction(myCallbackFunction);
// Run the first time without delay
console.log(iteratorFunction.next().value);
// Step to the next iteration every n seconds
window.setInterval(() => {
console.log(iteratorFunction.next().value);
}, 1000);
Update: Looks like OP wants to invoke the callback() method first. If that's the case, let count = 1 in the snippet above should be changed to let count = 0:
function* myFunction(callback) {
let count = 0;
while (true) {
let output;
if (count % 4 === 0)
output = callback();
else
output = myResultFunction();
count++;
yield output;
}
}
function myResultFunction() {
return 'myResultFunction(): called every count';
}
function myCallbackFunction() {
return 'myCallbackFunction(): called at every fourth count';
}
var iteratorFunction = myFunction(myCallbackFunction);
// Run the first time without delay
console.log(iteratorFunction.next().value);
// Step to the next iteration every n seconds
window.setInterval(() => {
console.log(iteratorFunction.next().value);
}, 1000);
You could store the functions in an array in the wanted order and use a closure over the index and increment this index after each call. Adjust if necessary.
function a() {
console.log('a');
}
function b() {
console.log('b');
}
var fn = [a, a, a, b];
setInterval((i => () => {
fn[i]();
i++;
i %= fn.length;
})(1), 100);
fn[0]();
var timer = 0;
var step = 100;
var callbackStep = 300;
function myFunction(callback){
setInterval( function() {
if(timer >= callbackStep && timer % callbackStep === 0) {
callback()
} else {
// myResultFunction(); dont really need this, but can be called.
}
timer += step
}, step);
}
myFunction(function(){console.log(`Once every ${callbackStep}ms. Current ${(timer ? timer : 100) / (step / 100 * callbackStep)}`);});

Simple Javascript Countdown how to update global from setintervals local function

I am pulling countdown data(just a number like 10,15..) from db and making it equal to global.
just under class.
countdown:any;
console.log(this.countdown);//i got data 10 sec
let downloadTimer=setInterval(function counter(countdown){
countdown--; // how to update this.countdown ?
console.log(countdown);
if(countdown <= 0){
clearInterval(downloadTimer);
console.log("time is up!");
}
},1000,this.countdown);
I am starting with sending this.countdown to counter parameter but then how do i update this.countdown from local counter function? because when setinterval iterates it always calls this.countdown so counter stucks at first this.countdown value.
If i do it without parameter i cant access this.counter from counter local function.
You are trying to pass a single scalar value, this.countdown, which is does, but you can't update that the same way you can an object or array and get the side effect of updating the original.
You could pass a reference to this and then use it to update the original:
class test {
constructor() {
this.countdown = 20
}
doit() {
console.log(this.countdown); //i got data 10 sec
let downloadTimer = setInterval(function counter(obj) {
obj.countdown--; // how to update this.countdown ?
console.log(obj.countdown);
if (obj.countdown <= 0) {
clearInterval(downloadTimer);
console.log("time is up!");
}
}, 200, this);
}
}
var t = new test
t.doit()
You could also use an arrow function to capture the value of this rather than passing it in:
class test {
constructor() {
this.countdown = 20
}
doit() {
console.log(this.countdown); //i got data 10 sec
let downloadTimer = setInterval(() => {
this.countdown--; // how to update this.countdown ?
console.log(this.countdown);
if (this.countdown <= 0) {
clearInterval(downloadTimer);
console.log("time is up!");
}
}, 200);
}
}
var t = new test
t.doit()

Javascript - telling setInterval to only fire x amount of times?

Is it possible to limit the amount of times that setInterval will fire in javascript?
You can call clearInterval() after x calls:
var x = 0;
var intervalID = setInterval(function () {
// Your logic here
if (++x === 5) {
window.clearInterval(intervalID);
}
}, 1000);
To avoid global variables, an improvement of the above would be:
function setIntervalX(callback, delay, repetitions) {
var x = 0;
var intervalID = window.setInterval(function () {
callback();
if (++x === repetitions) {
window.clearInterval(intervalID);
}
}, delay);
}
Then you can call the new setInvervalX() function as follows:
// This will be repeated 5 times with 1 second intervals:
setIntervalX(function () {
// Your logic here
}, 1000, 5);
I personally prefer to use setTimeout() spaced out to achieve the same effect
// Set a function to run every "interval" seconds a total of "x" times
var x = 10;
var interval = 1000;
for (var i = 0; i < x; i++) {
setTimeout(function () {
// Do Something
}, i * interval)
}
There's no clean up required with clearInterval()
You can enclose it to avoid variables leaking and it looks pretty clean :)
// Definition
function setIntervalLimited(callback, interval, x) {
for (var i = 0; i < x; i++) {
setTimeout(callback, i * interval);
}
}
// Usage
setIntervalLimited(function() {
console.log('hit'); // => hit...hit...etc (every second, stops after 10)
}, 1000, 10)
You can set a timeout that calls clearInterval.
This should work:
function setTimedInterval(callback, delay, timeout){
var id=window.setInterval(callback, delay);
window.setTimeout(function(){
window.clearInterval(id);
}, timeout);
}
You can use setTimeout and a for loop.
var numberOfTimes = 20;
delay = 1000;
for (let i = 0; i < numberOfTimes; i++) {
setTimeout( doSomething, delay * i);
}
This will clear the interval after 10 calls
<html>
<body>
<input type="text" id="clock" />
<script language=javascript>
var numOfCalls = 0;
var int=self.setInterval("clock()",1000);
function clock()
{
var d=new Date();
var t=d.toLocaleTimeString();
document.getElementById("clock").value=t;
numOfCalls++;
if(numOfCalls == 10)
window.clearInterval(int);
}
</script>
</form>
</body>
</html>
I made a small package that does this for NodeJS.
https://www.npmjs.com/package/count-interval
It's a drop-in replacement for setInterval (including parameter passing), but it takes an additional count parameter. This example prints a message once every second, but only 3 times.
const countInterval = require('./countInterval');
const timer = countInterval(() => {
console.log('fired!', new Date());
}, 1000, 3);
And for those of you preferring setTimeout and loving recursion here is my suggestion ;)
const setIntervalX = (fn, delay, times) => {
if(!times) return
setTimeout(() => {
fn()
setIntervalX(fn, delay, times-1)
}, delay)
}
Then as suggested you can call the new setInvervalX() function as follows:
// This will be repeated every for 5 times with 1 second intervals:
setIntervalX(function () {
// Your logic here
}, 1000, 5);
You can do this actually very simply with setTimeout() and an incremental counter.
var i = 0; // counter for the timer
function doSomething() {
console.log("1 second"); // your actual code here, alternatively call an other function here
if (++i < 10)
{ // only reset the timer when maximum of 10 times it is fired
console.log("reset the timer");
setTimeout(doSomething, 1000); // reset the timer
}
}
setTimeout(doSomething, 1000); // init the first
This answer is based on SO: Repeating setTimeout and a nice, neat and tidy small combination with this.
You can use Six
SetIntervalX: Limit the number of times that setInterval will fire
import { setIntervalX } from "https://deno.land/x/six/mod.ts";
import { randomNumber } from "https://deno.land/x/random_number/mod.ts";
const API_URL = "https://leap.deno.dev";
async function checkAPIStatus() {
const startTime = performance.now();
const randomYear = randomNumber({ min: 2000, max: 10_000 });
const response = await fetch(`${API_URL}/${randomYear}`);
const data = await response.json();
console.log(`Is ${randomYear} a leap year? ${data.leapYear}.`);
const entTime = performance.now();
console.log(`Request took ${(entTime - startTime) / 1000} seconds.`);
}
setIntervalX(checkAPIStatus, 2000, 15);
Web Page: https://ulti.js.org/six
Repository: https://github.com/UltiRequiem/six
It includes documentation, 100% code coverage, and examples!
Works on Deno, Node.js and the browser!

Categories

Resources