So right now, I am a beginner in coding and I'm having quite a few issues with the setInterval command. What I am trying to do is have a function that decreases a variable by 1 every time 5 seconds pass. However, although I have looked at many different threads with information about the setInterval command, none of them seem to fit my needs (although I may have missed something) and I have been unable to manipulate anything I have seen elsewhere to perform my function.
while (fullness <= 10) {
setInterval(hungry{ fullness--; }, 1000);
}
Why your code is wrong:
//There is no need to loop and call setInterval multiple times
//setInterval will fire the callback function every x milliseconds,
//In your example you have it firing every 1 second(1000 milliseconds)
//while (fullness <= 10) {
//setInterval(hungry{ fullness--; }, 1000);
//}
To fix this:
On page load (document.ready in jquery)
Do just one call to setInterval()
setInterval(function(){
if(fullness <= 10){
hungry{ fullness--; }; //Not sure about this line as it comes from your example
}
}, 5000); //Pass second parameter to setInterval of 5000 milliseconds (5 seconds wait)
You may be trying to use setInterval() in a synchronous way rather than asynchronously.
When you call setInterval(function, period) it only begins a timer that calls the given function every period milliseconds. After calling setInterval javascript will continue to execute the next lines of code right away. If you were to check for your fullness value right after the while loop ends, you might notice it hasn't changed (yet!).
I suggest that you write a new function to handle changing fullness and reacting to the change:
function updateHunger() {
fullness--;
if (fullness < 10) {
//Do something
}
else {
//You have to call clearInterval() to stop the timer
clearInterval(hungerTimer);
}
}
Then use setInterval like this:
//Using a variable to store the timer reference that we create
hungerTimer = setInterval(updateHunger, 5000);
Remember to declare the hungerTimer variable in a scope where it can be accessed from both updateHunger() and the method that calls setInterval().
You have to first set a variable for setInterval and then stop the iteration with clearInterval (important, otherwise the loop will iterate indefinitely). And check for fullness to be greater than 0.
var fullness = 10;
var timer = setInterval(function(){
if(fullness > 0){
fullness--;
}
else{
clearInterval(timer);
}
}, 5000);
Here is the working jsFiddle
The reason you are bumping into this is that JS runs in a single thread. Blocking it by waiting for 1 second would make the entire browser stall, which is why JS does not allow it and we do not have sleep() in JS, we have the Timers API.
But it's nonetheless nice to write straight up for-loops that look synchronous because that's how we "normally" think. That's why you can actually nowadays write something like this if using an engine with async and generator support:
// ES6 features
const sleeper = (x, timeout) =>
new Promise(resolve => setTimeout(resolve, timeout, x));
function* timer(count, timeout) {
for (let i = count; i >= 0; i--) {
yield sleeper(i, timeout);
}
}
async function main() {
for (let i of timer(10, 1000)) {
console.log(await i); // Blocks the main() function but not the JS main thread!
}
}
main();
console.log("The call to main() was non-blocking");
Related
I am working on the initial data pull for a project. It will be cached and further requests will be much less. I am attempting to space out my API requests every 5 seconds to avoid overloading the server and hitting the rate limit per their rules. It does not seem that my setTimeout() function is actually working as desired. I logged time stamps to see and all iterations seem to be happening at the exact same time. I think this somehow due to the asynchronous nature of javascript, but I'm not sure how to remedy it. Any help would be greatly appreciated.
Code Excerpt:
var leagues;
function getLeagues(){
var reqURL = "url";
var data = new XMLHttpRequest();
data.open("GET", reqURL);
data.responseType = "text";
data.send();
// parse data on load
data.onload = function() {
// League IDs
leagues = JSON.parse(data.response)
for (i = 0; i < 5; i++) {
delay(i); // iterate every 5 secs
}
};
}
function delay(i) {
setTimeout(() => {
var d = new Date();
console.log(d.getSeconds())
}, 5000);
}
You call delay to tell JS to do something in 5 seconds.
Then you immediately call delay to tell JS to do something in 5 seconds again.
So 5 seconds later the first delay timeout triggers, then immediately after that the second one triggers.
If you want to space them apart then you need to either:
Call delay the second time in the function that setTimeout calls so the second timer doesn't start under the first one is finished
Multiply your times so the first one is 5 seconds but the second is 10 seconds and so on
Refactor the code to use setInterval instead
setTimeout is a browser API that will guarantees not an exact delay time to execute after but a minimum time to execute a function so it's not related to js.
setTimeout cause the browser to set a timer after x milliseconds, when finished the function you pass will be in the event queue, but it won't necessarily execute, if event queue was completely empty, you are lucky and the function get executed immediately after 5 seconds, otherwise the function have to wait in queue until each function get executed before so we have (5 seconds + some times until the function get in the head of the queue then get executed).
calling setTimeout five times in sequence (using a for loop) with the same time delay will add the same function 5 consequent times in the event queue, all will be executed at the same time because of the same time delay used for all of them. so a solution would be to use different delay time for each function.
I'll suggest the solution for the same problem, because I faced it alot
Callback based solution
repeat(processingRequest, 5, 5000);
function processingRequest(){
console.log('Making request at', new Date().getTime());
}
function repeat(func, howManyTimes, milliSecondsInterval){
if(howManyTimes > 0)
delay(() => {
func();
howManyTimes--;
repeat(func, howManyTimes, milliSecondsInterval);
}, milliSecondsInterval);
}
function delay(func, milliSeconds){
setTimeout(func, milliSeconds);
}
Promise based solution(more preferred)
repeat(processingRequest, 5, 5000);
function processingRequest(){
console.log('Making request at', new Date().getTime());
}
function repeat(func, howManyTimes, milliSeconds){
delay(milliSeconds)
.then(() => {
func();
howManyTimes--;
if(howManyTimes > 0)
repeat(func, howManyTimes, milliSeconds);
});
}
function delay(milliSeconds){
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve();
}, milliSeconds);
});
}
using a library like rxjs(providing a repeat and delay) will make things even more simple
https://rxjs-dev.firebaseapp.com/api/operators/repeat
https://rxjs-dev.firebaseapp.com/api/operators/delay
even though not every application need rxjs, but we have to say it give the programmer a great power over clean sync or async operations
[References]
For further knowledge about Browser API & Event queue
Cool talk from Philip Roberts
https://youtu.be/8aGhZQkoFbQ?t=1165
from THE BEST great js resource I've found
https://github.com/getify/You-Dont-Know-JS/blob/1st-ed/async%20%26%20performance/ch1.md
You can use a Promise instead of a timeout. The setTimeout function will wait five seconds and all code will be executed, because it does not block the execution. A promise instead will do that:
async function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
};
You can use the promise inside of an async loop:
async function getLeagues(){
var reqURL = "url";
var data = new XMLHttpRequest();
data.open("GET", reqURL);
data.responseType = "text";
data.send();
// parse data on load
data.onload = function() {
// League IDs
leagues = JSON.parse(data.response)
const delays = [...new Array(5)]; // To have something to loop over
for await (const d of delays) {
await delay(5000);
}
};
}
function delay(i) {
setTimeout(() => {
var d = new Date();
console.log(d.getSeconds())
}, i * 5000);
}
The process of setting up the timeout i.e. the calls to setTimeout() — takes almost no time at all. If a succession of timeout requests is made, the delay value is the same for each one, then once that amount of time has elapsed.. all the timer handlers will be called consecutively rapidly. If you need the handlers to be called at intervals, you can either use setInterval(), which is called exactly like setTimeout() but will fire more than once after repeated delays of 5000, or instead, you can establish the timeouts and multiply the time value by your iteration counter i.e. 'i' in this case. The value of i is multiplied by the original delay value, so calling that 5 times in a loop will result in delays of 5 seconds, 10 seconds, 15 seconds, 20 seconds, and 25 seconds.
I'm writing a program in Javascript that takes input strings and then runs a simulation on each string. The user decides how fast, i.e. what the delay should be between processing each string. I'm using the setInterval() function to control this. However, I am running into the issue that longer strings may not be ready to process because the last string is still processing. This causes a slew of errors on my part. Here's some code to paint a better picture.
let testingInterval = setInterval(function () {
strprn.innerHTML = `<h2>${strings[i]}<\h2>`; // displays current string to user
if (i + 1 == strings.length) { // checks if should notify user all strings have been processed
checker.finalCheck = true;//the checker uses this flag to notify the user once the test completes
}
checker.check(strings[i]); //runs the check i.e. simulation
i++; // increments the counter iterating through the array (setup code not shown here)
if (i >= strings.length) {
clearInterval(testingInterval); //once we reach the end stop the interval iterating
evenOutResults(); // clean up answers function
updateTimeStamp(Date.now()); // for readability, I add a timestamp of when the results were generated
}
}, delay); // user specified delay
What I'm looking for is a way to honor the delay but also not begin the next call until the current string has finished processing.
Something like this logically (the code below freezes your browser XD):
function delayLoop() {
setTimeout(function () {
strprn.innerHTML = `<h2>${strings[i]}<\h2>`;
if (i + 1 == strings.length){
checker.finalCheck = true;
}
checker.check(strings[i]);
i++;
if (i < strings.length) {
// check if the current string has finished, if so call, else wait until the string is done
while (checker.processingFlag){
// console.log('Waiting for current string to finish');
}
delayLoop(); // call again
} else {
evenOutResults();
updateTimeStamp(Date.now());
}
}, delay);
Correct me if I'm wrong, but it seems like as though you want to have some kind of schedule of appointments that you'd like "messages" to be received at and if a message is not ready at the appointment, then you'd like it to reschedule to the next appointment. You can easily find the next available appointment with some kind of iteration
const nextCheckin = (lastCheckin, interval) => {
while (lastCheckin < Date.now())
last += delay
return last
}
Assuming the order of messages matters you can do something like such
const simulation = (strings, delay) => {
let checkin = Date.now() + delay
for (const str of strings) {
const result = simulate(str)
checkin = nextCheckin(checkin, delay)
console.log(`Waiting for: ${checkin-Date.now()}`)
while (Date.now() < checkin)
continue
reportWork(result)
}
}
The while loop will cause the event loop to hang, so maybe a call to setTimeout would be more appropriate, but whatever floats a boat.
Sorry, I should have clarified this more. Checker.check() is a function that uses a setInterval() to display an animation. The animation needs to be done for a set of objects. Because of the setInterval(), anytime we wait means javascript will try to execute the next lines of code. This means vanilla for-loops are out of the question.
My initial solution was to throw the for-loop iteration itself into a setTimeout(). This works as long as the delay is long enough for all the objects being iterated. Problem is the objects rarely are, so if an object was larger than the one it preceded and the delay was short then the whole animation crashed. In the end, Promises were the easiest solution.
let runLoop = async () => {
for(var i = 0; i < strings.length; i++){
strprn.innerHTML = `<h2>${strings[i]}<\h2>`;
console.log("about to await");
if (i + 1 == strings.length){
checker.finalCheck = true;
}
await new Promise(resolve => checker.check(resolve, strings[i]));
if (checker.finalCheck){
updateTimeStamp(Date.now());
}
}
}
runLoop();
For those who wonder onto this looking for an answer, the await pauses your execution until the resolve is met. You pass resolve onto your function, and inside the setInterval() code block, at the very end you call resolve(). In order to use the await, the whole thing gets wrapped up inside of an async.
I understand that Javascript does not have a delay(500) method, which would delay execution for 500 milliseconds, so I have been trying to get around that by using setTimeout and setInterval.
for(var i =0; i< 10; i++){
/* Animation Code */
var doNothing = function(){var m =5;}
setTimeout(doNothing, 50);
}
However, this does not seem to work. I essentially want some code that stops the execution for n milliseconds and then continues execution.
Practically speaking, you can't do this. Deal with it and find a callback-based way instead. Typically this means putting everything that should happen after the delay in the callback itself.
For example, you can't do this to make baz wait:
foo();
setTimeout(function() {
bar();
}, 500);
baz();
so you do the only thing you can:
foo();
setTimeout(function() {
bar();
baz();
}, 500);
The setInterval() Method wait a specified number of milliseconds, and then execute a specified function, and it will continue to execute the function, once at every given time-interval.
Syntax
window.setInterval("javascript function",milliseconds);
The window.setInterval() method can be written without the window prefix.
The first parameter of setInterval() should be a function.
How to Stop the Execution?
The clearInterval() method is used to stop further executions of the function specified in the setInterval() method.
Syntax
window.clearInterval(intervalVariable)
The window.clearInterval() method can be written without the window prefix.
To be able to use the clearInterval() method, you must use a global variable when creating the interval method:
myVar=setInterval("javascript function",milliseconds);
Then you will be able to stop the execution by calling the clearInterval() method.
good refrence
If you came from the language/framework/API background, where you could suspend the execution with something like Sleep, or process user input synchronously with something like DoEvents, it won't work in JavaScript.
There is no way you can block the JavaScript event loop with something like this, for a good reason: UI responsiveness. In JavaScript, everything is asynchronous. You can use setTimeout to do something upon a timer event, but the user is still able to access the UI between the timer events or even navigate away from the page.
To address your code fragment, what you are looking for is called an asynchronous state machine. It allows to preserve the state of the code between stop/continue (in your case, it's the state of the animation, although i variable is also a part of it):
(function()
{
var i = 0;
var nextStep = function()
{
if (i<10)
{
/* Animation Code */
i++;
setTimeout(nextStep, 500);
}
}
nextStep();
})();
It will be much easier to code when all browsers support the new yield keyword:
http://pag.forbeslindesay.co.uk
On a side note, some other answers suggest using setInterval. There is a subtle but important difference between delay and interval. Delay is the time between two steps. Interval is the time since the previous step started. If each step of animation takes 200ms, and you use the interval of 500ms, the actual delay between two steps will be 300ms, not 500ms as probably expected.
setInterval() - executes a function, over and over again, at specified time intervals
To pass a function as a string, be sure to append the function name with parentheses.
window.setInterval("someFunction()", 5000);
When passing a function pointer, do not include the parentheses.
window.setInterval(someFunction, 5000);
var timer_id=setInterval(doNothing,500);
If you want to stop the execution
make the timer_id variable global
clearInterval(timer_id);
Much cleaner and readable code would be if you use RxJS
Here is an example:
Rx.Observable
.interval(1000)
.take(10)
.subscribe((x) => console.log(`${x}: ${new Date().toLocaleTimeString()}`))
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/4.1.0/rx.lite.min.js"></script>
interval - is a time delay between your animation calls. In my example
it's 1000ms
take - number of times to execute subscribe - is function
that will be called every 1000ms for 10 times (in your case it will be
your animation code)
Here some something that could help.
function delay( s , callback )
{
var fct_ref = "tmp_" + Math.random().toString(36).replace(/[^a-z]+/g, '').substr(0, 6).toUpperCase();
var tmp_fct = ( callback !== undefined ) ? callback.toString().match(/^[^{]+\{(.*?)\}$/)[1] : "";
document.getElementsByTagName("body")[0].insertAdjacentHTML("beforeend","<div id='"+fct_ref+"' style='background-color:transparent;color:transparent;position:absolute;top:"+window.scrollY+"px;left:"+window.scrollX+"px;opacity:1;transition:all "+s+"s'>-</div>");
var func = new Function("return function transition"+fct_ref+"(e){ e.target.removeEventListener('transitionend' , transition"+fct_ref+", false ); "+tmp_fct+" ; document.getElementById('"+fct_ref+"').parentNode.removeChild(document.getElementById('"+fct_ref+"')); };")();
document.getElementById(""+fct_ref).addEventListener("transitionend", func , false );
document.getElementById(""+fct_ref).offsetHeight;
document.getElementById(""+fct_ref).style.opacity="0";
}
delay(1, function() { console.log("ANIMATION_1"); } );
delay(3, function() { console.log("ANIMATION_3"); } );
delay(5, function() { console.log("ANIMATION_5"); } );
This javascript code is fairly lengthy, but the most important part is the end where it posts:
httpwp['send'](paramswp);
I have tried without success to put a 10 second pause between each send. Normally it sends them all instantly.
full code http://pastebin.com/cEM7zksn
To delay 10 seconds before calling this, you could use setTimeout
setTimeout(function() { httpwp['send'](paramswp); }, 10000);
Or more simply:
setTimeout(function() { httpwp.send(paramswp); }, 10000);
The setTimeout() function does not pause execution for the specified time, it queues a function to be executed after the specified time. The line of code after setTimeout() will be executed immediately. So if you have the following code:
1 someFunction();
2 setTimeout(function(){console.log("From timeout");}, 10000);
3 console.log("After setTimeout()");
What will happen is on line 1 someFunction() will be called, then on line 2 an anonymous function will be queued to execute in 10 seconds time, then line 3 will execute, logging "After setTimeout()", and finally 10 seconds later the anonymous function will execute logging "From timeout".
If you want to code a loop where each iteration is spaced out by 10 seconds, rather than using a conventional for loop you write a function that uses setTimeout() to call itself:
// this for loop won't work
for(var i = 0; i < 20; i++) {
// do something
// pause for 10 seconds ---- can't be done
}
// so instead you do something like this:
function timeoutLoop(i, max) {
if (i < max) {
// do something
i++;
setTimeout(function(){timeoutLoop(i, max);}, 10000);
}
}
timeoutLoop(0, 20);
I found your code a little hard to read so I've not tried to integrate the above with it, but here is a really simple demo of the above working: http://jsfiddle.net/CrSEt/1/
Or here is a cleaner version that separates the actual processing from the loop function by using a callback: http://jsfiddle.net/CrSEt/
I'm sure if you play around a bit with the above you'll see how to get it to work in your code. You may want to consider setting subsequent timeouts from inside your ajax success callback.
Is there any way to call a function periodically in JavaScript?
The setInterval() method, repeatedly calls a function or executes a code snippet, with a fixed time delay between each call. It returns an interval ID which uniquely identifies the interval, so you can remove it later by calling clearInterval().
var intervalId = setInterval(function() {
alert("Interval reached every 5s")
}, 5000);
// You can clear a periodic function by uncommenting:
// clearInterval(intervalId);
See more # setInterval() # MDN Web Docs
Please note that setInterval() is often not the best solution for periodic execution - It really depends on what javascript you're actually calling periodically.
eg. If you use setInterval() with a period of 1000ms and in the periodic function you make an ajax call that occasionally takes 2 seconds to return you will be making another ajax call before the first response gets back. This is usually undesirable.
Many libraries have periodic methods that protect against the pitfalls of using setInterval naively such as the Prototype example given by Nelson.
To achieve more robust periodic execution with a function that has a jQuery ajax call in it, consider something like this:
function myPeriodicMethod() {
$.ajax({
url: ...,
success: function(data) {
...
},
complete: function() {
// schedule the next request *only* when the current one is complete:
setTimeout(myPeriodicMethod, 1000);
}
});
}
// schedule the first invocation:
setTimeout(myPeriodicMethod, 1000);
Another approach is to use setTimeout but track elapsed time in a variable and then set the timeout delay on each invocation dynamically to execute a function as close to the desired interval as possible but never faster than you can get responses back.
Everyone has a setTimeout/setInterval solution already. I think that it is important to note that you can pass functions to setInterval, not just strings. Its actually probably a little "safer" to pass real functions instead of strings that will be "evaled" to those functions.
// example 1
function test() {
alert('called');
}
var interval = setInterval(test, 10000);
Or:
// example 2
var counter = 0;
var interval = setInterval(function() { alert("#"+counter++); }, 5000);
Old question but..
I also needed a periodical task runner and wrote TaskTimer. This is also useful when you need to run multiple tasks on different intervals.
// Timer with 1000ms (1 second) base interval resolution.
const timer = new TaskTimer(1000);
// Add task(s) based on tick intervals.
timer.add({
id: 'job1', // unique id of the task
tickInterval: 5, // run every 5 ticks (5 x interval = 5000 ms)
totalRuns: 10, // run 10 times only. (set to 0 for unlimited times)
callback(task) {
// code to be executed on each run
console.log(task.id + ' task has run ' + task.currentRuns + ' times.');
}
});
// Start the timer
timer.start();
TaskTimer works both in browser and Node. See documentation for all features.
You will want to have a look at setInterval() and setTimeout().
Here is a decent tutorial article.
yes - take a look at setInterval and setTimeout for executing code at certain times. setInterval would be the one to use to execute code periodically.
See a demo and answer here for usage
Since you want the function to be executed periodically, use setInterval
function test() {
alert('called!');
}
var id = setInterval('test();', 10000); //call test every 10 seconds.
function stop() { // call this to stop your interval.
clearInterval(id);
}
The native way is indeed setInterval()/clearInterval(), but if you are already using the Prototype library you can take advantage of PeriodicalExecutor:
new PeriodicalUpdator(myEvent, seconds);
This prevents overlapping calls. From http://www.prototypejs.org/api/periodicalExecuter:
"it shields you against multiple parallel executions of the callback function, should it take longer than the given interval to execute (it maintains an internal “running” flag, which is shielded against exceptions in the callback function). This is especially useful if you use one to interact with the user at given intervals (e.g. use a prompt or confirm call): this will avoid multiple message boxes all waiting to be actioned."