Loop a function without changing pages [duplicate] - javascript

This question already has answers here:
Calling a function every 60 seconds
(15 answers)
Closed 5 years ago.
JQuery, how to call a function every 5 seconds.
I'm looking for a way to automate the changing of images in a slideshow.
I'd rather not install any other 3rd party plugins if possible.

You don't need jquery for this, in plain javascript, the following will work:
var intervalId = window.setInterval(function(){
// call your function here
}, 5000);
To stop the loop you can use:
clearInterval(intervalId)

you could register an interval on the page using setInterval, ie:
setInterval(function(){
//code goes here that will be run every 5 seconds.
}, 5000);

A good example where to subscribe a setInterval(), and use a clearInterval() to stop the forever loop:
function everyTime() {
console.log('each 1 second...');
}
var myInterval = setInterval(everyTime, 1000);
call this line to stop the loop:
clearInterval(myInterval);

Just a little tip for the first answer. If your function is already defined, reference the function but don't call it!!! So don't put any parentheses after the function name. Just like:
my_function(){};
setInterval(my_function,10000);

The functions mentioned above execute no matter if it has completed in previous invocation or not, this one runs after every x seconds once the execution is complete
// IIFE
(function runForever(){
// Do something here
setTimeout(runForever, 5000)
})()
// Regular function with arguments
function someFunction(file, directory){
// Do something here
setTimeout(someFunction, 5000, file, directory)
// YES, setTimeout passes any extra args to
// function being called
}

Both setInterval and setTimeout can work for you (as #Doug Neiner and #John Boker wrote both now point to setInterval).
See here for some more explanation about both to see which suits you most and how to stop each of them.

you can use window.setInterval and time must to be define in miliseconds, in below case the function will call after every single second (1000 miliseconds)
<script>
var time = 3670;
window.setInterval(function(){
// Time calculations for days, hours, minutes and seconds
var h = Math.floor(time / 3600);
var m = Math.floor(time % 3600 / 60);
var s = Math.floor(time % 3600 % 60);
// Display the result in the element with id="demo"
document.getElementById("demo").innerHTML = h + "h "
+ m + "m " + s + "s ";
// If the count down is finished, write some text
if (time < 0) {
clearInterval(x);
document.getElementById("demo").innerHTML = "EXPIRED";
}
time--;
}, 1000);
</script>

Related

javascript function does not work with passing a parameter [duplicate]

Please advise how to pass parameters into a function called using setInterval.
My example setInterval(funca(10,3), 500); is incorrect.
You need to create an anonymous function so the actual function isn't executed right away.
setInterval( function() { funca(10,3); }, 500 );
Add them as parameters to setInterval:
setInterval(funca, 500, 10, 3);
The syntax in your question uses eval, which is not recommended practice.
now with ES5, bind method Function prototype :
setInterval(funca.bind(null,10,3),500);
Reference here
setInterval(function(a,b,c){
console.log(a + b +c);
}, 500, 1,2,3);
//note the console will print 6
//here we are passing 1,2,3 for a,b,c arguments
// tested in node v 8.11 and chrome 69
You can pass the parameter(s) as a property of the function object, not as a parameter:
var f = this.someFunction; //use 'this' if called from class
f.parameter1 = obj;
f.parameter2 = this;
f.parameter3 = whatever;
setInterval(f, 1000);
Then in your function someFunction, you will have access to the parameters. This is particularly useful inside classes where the scope goes to the global space automatically and you lose references to the class that called setInterval to begin with. With this approach, "parameter2" in "someFunction", in the example above, will have the right scope.
setInterval(function,milliseconds,param1,param2,...)
Update: 2018 - use the "spread" operator
function repeater(param1, param2, param3){
alert(param1);
alert(param2);
alert(param3);
}
let input = [1,2,3];
setInterval(repeater,3000,...input);
You can use an anonymous function;
setInterval(function() { funca(10,3); },500);
By far the most practical answer is the one given by tvanfosson, all i can do is give you an updated version with ES6:
setInterval( ()=>{ funca(10,3); }, 500);
Quoting the arguments should be enough:
OK --> reloadIntervalID = window.setInterval( "reloadSeries('"+param2Pass+"')" , 5000)
KO --> reloadIntervalID = window.setInterval( "reloadSeries( "+param2Pass+" )" , 5000)
Note the single quote ' for each argument.
Tested with IE8, Chrome and FireFox
const designated = "1 jan 2021"
function countdown(designated_time){
const currentTime = new Date();
const future_time = new Date(designated_time);
console.log(future_time - currentTime);
}
countdown(designated);
setInterval(countdown, 1000, designated);
There are so many ways you can do this, me personally things this is clean and sweet.
The best solution to this answer is the next block of code:
setInterval(() => yourFunction(param1, param2), 1000);
I know this topic is so old but here is my solution about passing parameters in setInterval function.
Html:
var fiveMinutes = 60 * 2;
var display = document.querySelector('#timer');
startTimer(fiveMinutes, display);
JavaScript:
function startTimer(duration, display) {
var timer = duration,
minutes, seconds;
setInterval(function () {
minutes = parseInt(timer / 60, 10);
seconds = parseInt(timer % 60, 10);
minutes = minutes < 10 ? "0" + minutes : minutes;
seconds = seconds < 10 ? "0" + seconds : seconds;
display.textContent = minutes + ":" + seconds;
--timer; // put boolean value for minus values.
}, 1000);
}
This worked for me
let theNumber = document.getElementById('number');
let counter = 0;
function skills (counterInput, timer, element) {
setInterval(() => {
if(counterInput > counter) {
counter += 1;
element.textContent = `${counter} %`
}else {
clearInterval();
}
}, timer)
}
skills(70, 200, theNumber);
This works setInterval("foo(bar)",int,lang);.... Jon Kleiser lead me to the answer.
Another solution consists in pass your function like that (if you've got dynamics vars) :
setInterval('funca('+x+','+y+')',500);
You can use a library called underscore js. It gives a nice wrapper on the bind method and is a much cleaner syntax as well. Letting you execute the function in the specified scope.
http://underscorejs.org/#bind
_.bind(function, scope, *arguments)
That problem would be a nice demonstration for use of closures. The idea is that a function uses a variable of outer scope. Here is an example...
setInterval(makeClosure("Snowden"), 1000)
function makeClosure(name) {
var ret
ret = function(){
console.log("Hello, " + name);
}
return ret;
}
Function "makeClosure" returns another function, which has access to outer scope variable "name". So, basically, you need pass in whatever variables to "makeClosure" function and use them in function assigned to "ret" variable. Affectingly, setInterval will execute function assigned to "ret".
I have had the same problem with Vue app. In my case this solution is only works if anonymous function has declared as arrow function, regarding declaration at mounted () life circle hook.
Also, with IE Support > 9, you can pass more variables insider set interval that will be taken by you function. E.g:
function myFunc(arg1, arg2){};
setInterval(myFunc, 500, arg1, arg2);
Greetings!

Javascript - Pausing an IIFE output that has setTimeout and displays min/sec - Pomodoro Clock

I have two functions that display minutes and seconds. Inside the functions I'm using an IIFE with a setTimeout to calculate the time. After getting this, having a hard time figuring out how I could pause the display if pause button is clicked.
The timer works fine and displays correctly.
I realize this is probably not a good way to do it, but I spent so much time (trying to learn how to use IIFE) that I don't want to give up. If I have to, then I will scratch it.
Update - This timer will be getting input from the user. It might be 25 minutes. I want it to start counting down from there until it reaches 0, and the user able to pause at anytime.
let convertToSeconds = document.getElementById('timeValue').value * 60;
let seconds = 60;
function secondsCounter(time) {
// let flag = document.getElementById('pauseButton').value;
for (let i = seconds; i > 0; i--) {
(function(x) {
setTimeout(function() {
let remaining = seconds - x;
document.getElementById('displaySeconds').innerHTML = remaining;
console.log(remaining);
}, i * 1000);
})(i);
}
}
function counter() {
for (let i = convertToSeconds; i > 0; i--) {
(function(minutes) {
setTimeout(function() {
let remaining = Math.floor((convertToSeconds - minutes) / 60);
document.getElementById('displayMinutes').innerHTML = remaining;
console.log(remaining);
}, i * 1000);
setTimeout(function() {
secondsCounter(seconds);
}, i * 60000);
})(i);
}
secondsCounter(seconds);
}
I've tried a couple of things.
Using a flag and if statement around document.getElementById('displaySeconds').innerHTML = remaining; so if my pause button is clicked, the flag changes, and another setTimeout (10 minutes) is triggered. Doesn't stop the countdown on the DOM, it keeps going. I just wanted to see some reaction, but nothing happened. Something like:
function secondsCounter(time) {
let flag = document.getElementById('pauseButton').value;
for (let i = seconds; i > 0; i--) {
(function(x) {
setTimeout(function() {
let remaining = seconds - x;
if (flag === 'yes') {
document.getElementById('displaySeconds').innerHTML = remaining;
console.log(remaining);
} else {
setTimeout(function() {
console.log(remaining);
}, 10000);
}
}, i * 1000);
})(i);
}
}
Using a setInterval and clearInterval that didn't do anything.
Is this possible? Not sure where else to look. Thank you
You can't stop/pause a setTimeout or clearTimeout without making a reference to the timer, storing it and then calling clearTimeout(timer) or clearInterval(timer).
So, instead of: setTimeout(someFunciton)
You need: timer = setTimeout(someFunciton)
And, the timer variable needs to be declared in a scope that is accessible to all functions that will use it.
See setTimeout() for details.
Without a reference to the timer, you will not be able to stop it and that's caused you to go on a wild goose chase for other ways to do it, which is overthinking what you actually need.
In the end, I think you should just have one function that does all the counting down so that you only have one timer to worry about.
Lastly, you can use the JavaScript Date object and its get / set Hours, Minutes and Seconds methods to take care of the reverse counting for you.
(function() {
// Ask user for a time to start counting down from.
var countdown = prompt("How much time do you want to put on the clock? (hh:mm:ss)");
// Take that string and split it into the HH, MM and SS stored in an array
var countdownArray = countdown.split(":")
// Extract the individual pieces of the array and convert to numbers:
var hh = parseInt(countdownArray[0],10);
var mm = parseInt(countdownArray[1],10);
var ss = parseInt(countdownArray[2],10);
// Make a new date and set it to the countdown value
var countdownTime = new Date();
countdownTime.setHours(hh, mm, ss);
// DOM object variables
var clock = null, btnStart = null, btnStop = null;
// Make a reference to the timer that will represent the running clock function
var timer = null;
window.addEventListener("DOMContentLoaded", function () {
// Make a cache variable to the DOM element we'll want to use more than once:
clock = document.getElementById("clock");
btnStart = document.getElementById("btnStart");
btnStop = document.getElementById("btnStop");
// Wire up the buttons
btnStart.addEventListener("click", startClock);
btnStop.addEventListener("click", stopClock);
// Start the clock
startClock();
});
function startClock() {
// Make sure to stop any previously running timers so that only
// one will ever be running
clearTimeout(timer);
// Get the current time and display
console.log(countdownTime.getSeconds());
countdownTime.setSeconds(countdownTime.getSeconds() - 1);
clock.innerHTML = countdownTime.toLocaleTimeString().replace(" AM", "");
// Have this function call itself, recursively every 900ms
timer = setTimeout(startClock, 900);
}
function stopClock() {
// Have this function call itself, recursively every 900ms
clearTimeout(timer);
}
}());
<div id="clock"></div>
<button id="btnStart">Start Clock</button>
<button id="btnStop">Stop Clock</button>

Trouble with changing image src content

I have a function that should postpone the call for the next function :
function waitFunc( func, time )
{
var startTime = performance.now();
var currTime = performance.now();
while ( (currTime - startTime) <= (time / 1))
{
currTime = performance.now();
}
func();
}
Another two function that i have are supposed to change the content of the tag i have in the body:
function showPlus()
{
//display plus
pictureImg.src = plus;
//blank only the form that contains input
inputForm.style.display="none";
pictureImg.style.display="block";
//after timeout start "showPicture" function
waitFunc(showPicture, 250);
//setTimeout(showPicture, 250);
}
function showPicture()
{
//generate picture pass
imgName = "../images/Slide"+ i + ".PNG";
if (i < 100)
{
//increase variable i by 1
++i;
//blank only the form that contains input
inputForm.style.display="none";
pictureImg.style.display="block";
//display picture
pictureImg.src = imgName;
//after timeout start "showForm" function
waitFunc(showForm, 750);
//setTimeout(showForm, 750);
}
}
In the html:
<img src="../images/Blank.png" id="pictures" name="pictures"/>
Currently i am trying to call to waitFunc function from showPlus function and i expect that showPicture function would be called after the timeout. PROBLEM: When i use waitFunc function the content does not change as it suppose. However, when i use setTimeout function everything works just great.
Can some please assist me (i hope that this is not a stupid question)?
P.S. you can find the page here.
Thank you!
EDIT: You can also find a jsfiddle here. Notice that the fiddle is using setTimeout so you can see how it is supposed to work; if you comment the setTimeout and uncomment the waitFunc line next to it, then you will be able to see the issue.
There's a function called setTimeout() which does exactly the same functionality you need. Why don't you use it instead of building JavaScript all over again.
Also, performance.now(); isn't supported in all the browsers:
https://developer.mozilla.org/en-US/docs/Web/API/Performance.now
Also, your function shouldn't work at all:
var startTime = performance.now();
var currTime = performance.now();
Here you should have startTime == currTime because you're setting the same value in less than 1 millisecond.
while((currTime - startTime) <= (time / 1))
Here, (currTime - startTime) should be equal to zero, and (time / 1) is equal to time.
I don't understand what you're trying to do, but if you're looking to "pass a function as a parameter", your question is a duplicate: Pass a JavaScript function as parameter
You must know that javascript is excuted in a single thread. If you run a wait function implemented using a while statement the main thread of the page will be frozen.
The difference of you waitFunc implementation and the setTimeout of javascript is that the setTimeout function run in a separated thread. By other side your function is executed synchronous. By example the showPicture function will take 75000 ms on it run because the loop will wait on each waiFunc 750 ms.
I hope that this help.
This code works perfect. When the page load the main thread is busy for 3 seconds set the 3.jpg image and after 2 seconds the image return to be the first image again. This is using you function and the settimeout.
<!DOCTYPE html>
<html>
<head>
<title></title>
<script src="js/lib/jquery-2.1.1.js"></script>
<script>
function waitFunc( func, time )
{
var startTime = performance.now();
var currTime = performance.now();
while ( (currTime - startTime) <= (time / 1))
{
currTime = performance.now();
}
func();
}
$(function(){
waitFunc(function(){
$('#dd').prop('src', '3.jpg');
}, 3000);
setTimeout(function(){
$('#dd').prop('src', 'A_Girl_In_The_Horizon_by_yeg0.jpg');
}, 2000)
});
</script>
</head>
<body>
<img id='dd' src="A_Girl_In_The_Horizon_by_yeg0.jpg">
</body>
</html>
I ran some tests and, as I mentioned in the question comment, the issue seems to be that the waitFunc that you use freezes the browser before it is able to load the picture and change the display.
I got something kind of working, but again, you may not like it: the solution would consist on using setTimeout (with a low milliseconds value: 1-20) to call waitFunc (with the value that you want minus the 1-20 milliseconds). Something like this:
setTimeout(waitAuxForm, 1);
And then you have the function:
function waitAuxForm() { waitFunc(showForm, 749); }
I have put it in a jsfiddle and you can see it working here.
This solution presents some issues too:
You have to rely on setTimeout for a low amount of time (you may not like this).
You may need more than 1-20 milliseconds to load the pictures (you may want to preload them and once cached, it would work even with a value of 1).
I hope it helps :)
Okay, so I was able to get this to work with the information you provided. Right out of the gates, looking at what you have, nothing is defined. However, assuming that you have inputForm and pictureImg defined correctly in both of the last functions, the only thing you're missing is to define i.
function showPicture()
{
var i = 0;
//generate picture pass
imgName = "../images/Slide"+ i + ".PNG";
[...]
}
I couldn't find anything wrong with your waitFunc function. If you substitute in a simpler function, it works as intended.
function waitFunc( func, time )
{
[...]
while ( (currTime - startTime) <= (time / 1))
{
currTime = performance.now();
console.log(time); // log so you can see, for testing
}
func();
}
waitFunc(function(){console.log("Hello, world!");}, 750); // wait 750 ms, then say "Hello, world!"

Accurately run a function when the minute changes?

How could I accurately run a function when the minute changes? Using a setInterval could work if I trigger it right when the minute changes. But I'm worried setInterval could get disrupted by the event-loop in a long-running process and not stay in sync with the clock.
How can I run a function accurately when the minute changes?
First off, you should use setInterval for repeating timers, since it (tries to) guarantee periodic execution, i.e. any potential delays will not stack up as they will with repeated setTimeout calls. This will execute your function every minute:
var ONE_MINUTE = 60 * 1000;
function showTime() {
console.log(new Date());
}
setInterval(showTime, ONE_MINUTE);
Now, what we need to do is to start this at the exact right time:
function repeatEvery(func, interval) {
// Check current time and calculate the delay until next interval
var now = new Date(),
delay = interval - now % interval;
function start() {
// Execute function now...
func();
// ... and every interval
setInterval(func, interval);
}
// Delay execution until it's an even interval
setTimeout(start, delay);
}
repeatEvery(showTime, ONE_MINUTE);
This may be an idea. The maximum deviation should be 1 second. If you want it to be more precise, lower the milliseconds of setTimeout1.
setTimeout(checkMinutes,1000);
function checkMinutes(){
var now = new Date().getMinutes();
if (now > checkMinutes.prevTime){
// do something
console.log('nextminute arrived');
}
checkMinutes.prevTime = now;
setTimeout(checkChange,1000);
}
1 But, see also this question, about accuracy of timeouts in javascript
You can try to be as accurate as you can, setting a timeout each X milliseconds and check if the minute has passed and how much time has passed since the last invocation of the function, but that's about it.
You cannot be 100% sure that your function will trigger exactly after 1 minute, because there might be something blocking the event-loop then.
If it's something vital, I suggest using a cronjob or a separate Node.js process specifically for that (so you can make sure the event loop isn't blocked).
Resources:
http://www.sitepoint.com/creating-accurate-timers-in-javascript/
I've put up a possible solution for you:
/* Usage:
*
* coolerInterval( func, interval, triggerOnceEvery);
*
* - func : the function to trigger
* - interval : interval that will adjust itself overtime checking the clock time
* - triggerOnceEvery : trigger your function once after X adjustments (default to 1)
*/
var coolerInterval = function(func, interval, triggerOnceEvery) {
var startTime = new Date().getTime(),
nextTick = startTime,
count = 0;
triggerOnceEvery = triggerOnceEvery || 1;
var internalInterval = function() {
nextTick += interval;
count++;
if(count == triggerOnceEvery) {
func();
count = 0;
}
setTimeout(internalInterval, nextTick - new Date().getTime());
};
internalInterval();
};
The following is a sample usage that prints the timestamp once every minute, but the time drift is adjusted every second
coolerInterval(function() {
console.log( new Date().getTime() );
}, 1000, 60);
It's not perfect, but should be reliable enough.
Consider that the user could switch the tab on the browser, or your code could have some other blocking tasks running on the page, so a browser solution will never be perfect, it's up to you (and your requirements) to decide if it's reliable enough or not.
Tested in browser and node.js
sleeps until 2 seconds before minute change then waits for change
you can remove logging as it gets pretty cluttered in log otherwise
function onMinute(cb,init) {
if (typeof cb === 'function') {
var start_time=new Date(),timeslice = start_time.toString(),timeslices = timeslice.split(":"),start_minute=timeslices[1],last_minute=start_minute;
var seconds = 60 - Number(timeslices[2].substr(0,2));
var timer_id;
var spin = function (){
console.log("awake:ready..set..");
var spin_id = setInterval (function () {
var time=new Date(),timeslice = time.toString(),timeslices = timeslice.split(":"),minute=timeslices[1];
if (last_minute!==minute) {
console.log("go!");
clearInterval(spin_id);
last_minute=minute;
cb(timeslice.split(" ")[4],Number(minute),time,timeslice);
console.log("snoozing..");
setTimeout(spin,58000);
}
},100);
};
setTimeout(spin,(seconds-2)*1000);
if (init) {
cb(timeslice.split(" ")[4],Number(start_minute),start_time,timeslice,seconds);
}
}
}
onMinute(function (timestr,minute,time,timetext,seconds) {
if (seconds!==undefined) {
console.log("started waiting for minute changes at",timestr,seconds,"seconds till first epoch");
} else {
console.log("it's",timestr,"and all is well");
}
},true);
My first thought would be to use the Date object to get the current time. This would allow you to set your set interval on the minute with some simple math. Then since your worried about it getting off, every 5-10 min or whatever you think is appropriate, you could recheck the time using a new date object and readjust your set interval accordingly.
This is just my first thought though in the morning I can put up some code(its like 2am here).
This is a fairly straightforward solution ... the interval for the timeout is adjusted each time it's called so it doesn't drift, with a little 50ms safety in case it fires early.
function onTheMinute(callback) {
const remaining = 60000 - (Date.now() % 60000);
setTimeout(() => {
callback.call(null);
onTheMinute(callback);
}, remaining + (remaining < 50 ? 60000 : 0));
}
Here's yet another solution based on #Linus' post and #Brad's comment. The only difference is it's not working by calling the parent function recursively, but instead is just a combination of setInterval() and setTimeout():
function callEveryInterval(callback, callInterval){
// Initiate the callback function to be called every
// *callInterval* milliseconds.
setInterval(interval => {
// We don't know when exactly the program is going to starts
// running, initialize the setInterval() function and, from
// thereon, keep calling the callback function. So there's almost
// surely going to be an offset between the host's system
// clock's minute change and the setInterval()'s ticks.
// The *delay* variable defines the necessary delay for the
// actual callback via setTimeout().
let delay = interval - new Date()%interval
setTimeout(() => callback(), delay)
}, callInterval, callInterval)
}
Small, maybe interesting fact: the callback function only begins executing on the minute change after next.
The solution proposed by #Linus with setInterval is in general correct, but it will work only as long as between two minutes there are exactly 60 seconds. This seemingly obvious assumption breaks down in the presence of a leap second or, probably more frequently, if the code runs on a laptop that get suspended for a number of seconds.
If you need to handle such cases it is best to manually call setTimeout adjusting every time the interval. Something like the following should do the job:
function repeatEvery( func, interval ) {
function repeater() {
repeatEvery( func, interval);
func();
}
var now = new Date();
var delay = interval - now % interval;
setTimeout(repeater, delay);
}

Change millisec for window.setInterval function

I used window.setInterval function. this function includes 3 arguments :
setInterval(code,millisec,lang)
I used that like this:
var counter = 1;
window.setInterval(function() {}, 1000 * ++counter);
but when first time set timer (second argument), is not changed and that act Like below code:
window.setInterval(function() {}, 1000);
please write correct code for change timer
Use window.setTimeout instead.
var delay = 1000;
function myTimer() {
// do whatever
window.setTimeout(myTimer, delay);
}
window.setTimeout(myTimer, delay);
You can manipulate delay in the body of your function.
Your problem is that javascript first execute '1000 * ++counter' once and then do not update the time interval.
You should try to use a timeout instead: https://developer.mozilla.org/en/DOM/window.setTimeout
And create a new time out with the new value every time your time out function is called.
Sounds like what you're after is not setInterval but rather setTimeout in a loop:
var counter = 1;
for (var i = 1; i <= 3; i++) {
window.setTimeout(function() {
alert("#" + counter);
counter++;
}, i * 1000);
}
This will execute three different "timers" one after the other.
Live test case: http://jsfiddle.net/86DRd/

Categories

Resources