My JavaScript loop is an infinite loop? - javascript

I'm new to programming, so please don't be harsh with my skills. Anyways, here is my code, I'm attempting to make a simple countdown loop.
var number = 30;
var countdown = true;
while(countdown === true) {
subtract();
if(number === 0) {
countdown = false;
}
}
function subtract() {
setTimeout(function() {
console.log(number);
number = number - 1;
}, 1000);
}
What did I do wrong?

Javascript has function-level block execution. One function runs to completion before another function is given ability to execute. Your while loop is maintaining the execution baton, so the other functions in setTimeout are never given a chance.

although javascript is called asynchonous in this case it does not call the subtract function until the first one is finished. (details http://ejohn.org/blog/how-javascript-timers-work/)
this should work
var number = 30;
setTimeout(function() {
console.log(number);
number = number - 1;
}, 1000);

setInterval is the function to set a function to run periodically. https://developer.mozilla.org/en-US/docs/Web/API/Window.setInterval
var number = 30;
var countdown = true;
var timer;
function update(){
console.log(number);
number = number - 1;
if (number === 0)
clearInterval(timer);
}
timer = setInterval(update, 1000);

When using the setTimeout function you actualy call a function after X miliseconds (in this case X=1000, which is 1 second).
'While' is the function you want to do the countdown with, right? So in your subtract function just write:
console.log(number);
number = number - 1;
You can also drop the subtract function and just write:
while(countdown === true) {
console.log(number);
number = number - 1;
if(number === 0) {
countdown = false;
}
}
Or drop the while function:
function subtract() {
id(countdown === true)
setTimeout(function() {
console.log(number);
number = number - 1;
subtract();
}, 1000);
else countdown = false;
}
subtract();

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

Creating a variable counter in javascript with variable speed

I'm having a problem.
I want to make a counter that counts from 1 to 9 and repeats.
The time between the counts should be variable (1 to 10 seconds in the same series).
Sometimes, it should add 1, sometimes 2 (so sometimes skip one number).
Is that possible with javascript?
Thank you in advance.
This is the code I have, but is only counts, does not skip a number sometimes and the time to count is fixed at 500 ms.
<div id="value">1</div>
<script>
function animateValue(id){
var obj = document.getElementById(id);
var current = obj.innerHTML;
setInterval(function(){
obj.innerHTML = current++;
},500);
}
animateValue('value');
</script>
</html>````
First, a JSFiddle:
http://jsfiddle.net/5k0xsrj6/embedded/result/
JSFiddle with larger, stylized text:
https://jsfiddle.net/9f4vgLbx/embedded/result
Edit: I see you're not familiar with JavaScript. I've included non-ES6 JavaScript as well.
The biggest issue you'll face with your code is the use of setInterval, as you want a variable timer.
Instead of setInterval, consider a function that calls itself and sets a timer. Once the setTimeout is called, it will invoke the function again to set another timeout, effectively creating an interval.
Non ES6 Script:
var el = document.body;
var max_count = 9;
var current_count = 1;
// Function which sets our timer
function timer(delay) {
// Set a timeout with our passed `delay` arg
setTimeout(function () {
// Adds either 1 or 2 based on the return value of getIteration
current_count += getIteration();
// As we have a max, reset to 1 if we're over
if (current_count > max_count) {
current_count = 1;
}
// Update innerHTML
writer();
// Call next iteration
loop();
}, delay);
}
// Writes our innerHTML
function writer() {
el.innerHTML = current_count;
}
// Returns 1000 through 10000
function getDelay() {
return Math.ceil(Math.random() * 10) * 1000;
}
// Returns either 1 or 2
function getIteration() {
return Math.ceil(Math.random() * 2);
}
// Our main function to loop
function loop() {
// getDelay will return a value between 1000 - 10000
timer(getDelay());
}
// Sets Initial Value
writer();
// Main
loop();
Original:
Here's an example of the code on the JSFiddle. I've included comments to hopefully explain the logic.
{
const el = document.body;
const max_count = 9;
let current_count = 1;
// Function which sets our timer
const timer = delay => {
setTimeout(() => {
current_count += getIteration();
if (current_count > max_count) {
current_count = 1;
}
// Update innerHTML
writer();
// Call next iteration
main();
}, delay);
}
// Writes our innerHTML
const writer = (str, log) => {
if (log) {
console.log(str);
} else {
el.innerHTML = `Current count: ${current_count}`;
}
}
// Returns 1000 through 10000
const getDelay = () => {
return Math.ceil(Math.random() * 10) * 1000;
}
// Returns either 1 or 2
const getIteration = () => {
return Math.ceil(Math.random() * 2);
}
// Our main function to loop
const main = () => {
const delay = getDelay();
writer(`Next delay is ${delay}ms`, true);
timer(delay);
}
// Set Initial Value
writer();
// Main
main();
}
Hope this helps! If you have any questions, feel free to ask!

clearInterval does not stop the interval operation

I'm working on a timer, and would like the setInterval() operation to terminate when the counter reaches zero. Further, I would like the function to be "turned off" if you will, so that I can reset the value that is fed into the timer, without the timer starting to decrement again.
When I configure the code like this:
function countdown(){
var intervalKill = setInterval(function(){
var start = document.getElementById("startValue").innerHTML;
if (start > 1){
var time_left = start - 1;
document.getElementById("startValue").innerHTML = time_left;
} else if (start === 1) {
clearInterval(intervalKill)
}
}, 1000);
}
I get it running perfectly well, however if it reaches 1, and I reset the timer, it will start counting down instantly again.
When I code it like this:
function countdown(){
var intervalKill = setInterval(function(){
var start = document.getElementById("startValue").innerHTML;
if (start > 1){
var time_left = start - 1;
document.getElementById("startValue").innerHTML = time_left;
} else if (start === 1) {
clearInterval(intervalKill);
break;
}
}, 1000);
}
The function just does not run at all. Can someone shed some light on what is going on here and how to get it to work?
function countdown(){
var intervalKill = setInterval(function(){
var start = document.getElementById("startValue").innerHTML;
if (start > 1){
var time_left = start - 1;
document.getElementById("startValue").innerHTML = time_left;
} else if (+start === 1) {
clearInterval(intervalKill);
// break; <-- not necessary
}
}, 1000);
}
Either parse the start to integer using unary + or parseInt or use == instead of === since the latter checks for type information as well.
innerHTML returns a string.

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)}`);});

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