It's there a way to configure the setInterval method of javascript to execute the method immediately and then executes with the timer
It's simplest to just call the function yourself directly the first time:
foo();
setInterval(foo, delay);
However there are good reasons to avoid setInterval - in particular in some circumstances a whole load of setInterval events can arrive immediately after each other without any delay. Another reason is that if you want to stop the loop you have to explicitly call clearInterval which means you have to remember the handle returned from the original setInterval call.
So an alternative method is to have foo trigger itself for subsequent calls using setTimeout instead:
function foo() {
// do stuff
// ...
// and schedule a repeat
setTimeout(foo, delay);
}
// start the cycle
foo();
This guarantees that there is at least an interval of delay between calls. It also makes it easier to cancel the loop if required - you just don't call setTimeout when your loop termination condition is reached.
Better yet, you can wrap that all up in an immediately invoked function expression which creates the function, which then calls itself again as above, and automatically starts the loop:
(function foo() {
...
setTimeout(foo, delay);
})();
which defines the function and starts the cycle all in one go.
I'm not sure if I'm understanding you correctly, but you could easily do something like this:
setInterval(function hello() {
console.log('world');
return hello;
}(), 5000);
There's obviously any number of ways of doing this, but that's the most concise way I can think of.
I stumbled upon this question due to the same problem but none of the answers helps if you need to behave exactly like setInterval() but with the only difference that the function is called immediately at the beginning.
Here is my solution to this problem:
function setIntervalImmediately(func, interval) {
func();
return setInterval(func, interval);
}
The advantage of this solution:
existing code using setInterval can easily be adapted by substitution
works in strict mode
it works with existing named functions and closures
you can still use the return value and pass it to clearInterval() later
Example:
// create 1 second interval with immediate execution
var myInterval = setIntervalImmediately( _ => {
console.log('hello');
}, 1000);
// clear interval after 4.5 seconds
setTimeout( _ => {
clearInterval(myInterval);
}, 4500);
To be cheeky, if you really need to use setInterval then you could also replace the original setInterval. Hence, no change of code required when adding this before your existing code:
var setIntervalOrig = setInterval;
setInterval = function(func, interval) {
func();
return setIntervalOrig(func, interval);
}
Still, all advantages as listed above apply here but no substitution is necessary.
You could wrap setInterval() in a function that provides that behavior:
function instantGratification( fn, delay ) {
fn();
setInterval( fn, delay );
}
...then use it like this:
instantGratification( function() {
console.log( 'invoked' );
}, 3000);
Here's a wrapper to pretty-fy it if you need it:
(function() {
var originalSetInterval = window.setInterval;
window.setInterval = function(fn, delay, runImmediately) {
if(runImmediately) fn();
return originalSetInterval(fn, delay);
};
})();
Set the third argument of setInterval to true and it'll run for the first time immediately after calling setInterval:
setInterval(function() { console.log("hello world"); }, 5000, true);
Or omit the third argument and it will retain its original behaviour:
setInterval(function() { console.log("hello world"); }, 5000);
Some browsers support additional arguments for setInterval which this wrapper doesn't take into account; I think these are rarely used, but keep that in mind if you do need them.
Here's a simple version for novices without all the messing around. It just declares the function, calls it, then starts the interval. That's it.
//Declare your function here
function My_Function(){
console.log("foo");
}
//Call the function first
My_Function();
//Set the interval
var interval = window.setInterval( My_Function, 500 );
There's a convenient npm package called firstInterval (full disclosure, it's mine).
Many of the examples here don't include parameter handling, and changing default behaviors of setInterval in any large project is evil. From the docs:
This pattern
setInterval(callback, 1000, p1, p2);
callback(p1, p2);
is identical to
firstInterval(callback, 1000, p1, p2);
If you're old school in the browser and don't want the dependency, it's an easy cut-and-paste from the code.
I will suggest calling the functions in the following sequence
var _timer = setInterval(foo, delay, params);
foo(params)
You can also pass the _timer to the foo, if you want to clearInterval(_timer) on a certain condition
var _timer = setInterval(function() { foo(_timer, params) }, delay);
foo(_timer, params);
For someone needs to bring the outer this inside as if it's an arrow function.
(function f() {
this.emit("...");
setTimeout(f.bind(this), 1000);
}).bind(this)();
If the above producing garbage bothers you, you can make a closure instead.
(that => {
(function f() {
that.emit("...");
setTimeout(f, 1000);
})();
})(this);
Or maybe consider using the #autobind decorator depending on your code.
You can set a very small initial delay-time (e.g. 100) and set it to your desired delay-time within the function:
var delay = 100;
function foo() {
console.log("Change initial delay-time to what you want.");
delay = 12000;
setTimeout(foo, delay);
}
To solve this problem , I run the function a first time after the page has loaded.
function foo(){ ... }
window.onload = function() {
foo();
};
window.setInterval(function()
{
foo();
}, 5000);
This example builds on #Alnitak's answer, but uses await Promise for finer granularity of control within the loop cycle.
Compare examples:
let stillGoing = true;
(function foo() {
console.log('The quick brown fox did its thing');
if (stillGoing) setTimeout(foo, 5000);
})();
foo();
In the above example we call foo() and then it calls itself every 5 seconds.
But if, at some point in the future, we set stillGoing to false in order to stop the loop, we'll still get an extra log line even after we've issued the stop order. This is because at any given time, before we set stillGoing to false the current iteration will have already created a timeout to call the next iteration.
If we instead use await Promise as the delay mechanism then we have an opportunity to stop the loop before calling the next iteration:
let stillGoing = true;
(async function foo() {
console.log('The quick brown fox did its thing');
await new Promise(resolve => setTimeout(resolve, 5000));
if (stillGoing) foo();
})();
foo();
In the second example we start by setting a 5000ms delay, after which we check the stillGoing value and decide whether calling another recursion is appropriate.
So if we set stillGoing to false at any point, there won't be that one extra log line printed after we set the value.
The caveat is this requires the function to be async, which may or may not be an option for a given use.
For Those using React, here is how I solve this problem:
const intervalRef = useRef(0);
useEffect(() => {
if (condition is true){
if (intervalRef.current === 0) {
callMyFunction();
}
const interval = setInterval(() => {
callMyFunction();
}, 5_000);
intervalRef.current = interval;
} else {
clearInterval(intervalRef.current);
}
}, [deps]);
// YCombinator
function anonymous(fnc) {
return function() {
fnc.apply(fnc, arguments);
return fnc;
}
}
// Invoking the first time:
setInterval(anonymous(function() {
console.log("bar");
})(), 4000);
// Not invoking the first time:
setInterval(anonymous(function() {
console.log("foo");
}), 4000);
// Or simple:
setInterval(function() {
console.log("baz");
}, 4000);
Ok this is so complex, so, let me put it more simple:
function hello(status ) {
console.log('world', ++status.count);
return status;
}
setInterval(hello, 5 * 1000, hello({ count: 0 }));
If you can use RxJS, there is something called timer():
import { Subscription, timer } from 'rxjs';
const INITIAL_DELAY = 1;
const INTERVAL_DELAY = 10000;
const timerSubscription = timer(INITIAL_DELAY, INTERVAL_DELAY)
.subscribe(() => {
this.updateSomething();
});
// when destroying
timerSubscription.unsubscribe();
With ES2017, it may be preferable to avoid setInterval altogether.
The following solution has a much cleaner execution flow, prevents issues if the function takes longer than the desired time to complete, and allows for asynchronous operations.
const timeout = (delayMs) => new Promise((res, _rej) => setTimeout(res, delayMs));
const DELAY = 1_000;
(async () => {
while (true) {
let start_time = Date.now();
// insert code here...
let end_time = Date.now();
await timeout(DELAY - (end_time - start_time));
}
})();
There's a problem with immediate asynchronous call of your function, because standard setTimeout/setInterval has a minimal timeout about several milliseconds even if you directly set it to 0. It caused by a browser specific work.
An example of code with a REAL zero delay wich works in Chrome, Safari, Opera
function setZeroTimeout(callback) {
var channel = new MessageChannel();
channel.port1.onmessage = callback;
channel.port2.postMessage('');
}
You can find more information here
And after the first manual call you can create an interval with your function.
actually the quickest is to do
interval = setInterval(myFunction(),45000)
this will call myfunction, and then will do it agaian every 45 seconds which is different than doing
interval = setInterval(myfunction, 45000)
which won't call it, but schedule it only
Related
I have looked around, tried several solutions and have not been able to find a solution :/
What I am looking to do is to have a loop that runs every second which contains events that are fired with different delays depending on the event type and conditions such event type pertains.
Tried self building the infinite loop and logic with while(true) and counters, as well as using setInterval and setTimeout, but all result into the same end result (result: see bottom of the question (based on code examples that use setInterval and setTimeout)).
This result is due to (or at least so I believe, would be nice if someone can confirm) a situation where my callstack contains new every second invocations of the whole loop and X amount of non processed eventY's that have been invoked -> the very first run the behavior is as expected, but after this the callstack begins to accumulate the non processed event Y's and prints them out every second or per the speed of the main loop.
some example code to explain (using setInterval and setTimeout):
function start() {
setInterval(eventList, 1000);
};
function eventList() {
console.log("foo")
eventY();
};
async function eventY() {
await newTimeout(0,5).then(() => {
console.log("bar");
})
};
function newTimeout (minutes, seconds) {
let counter = (minutes*60+seconds)*1000;
return new Promise(resolve => setTimeout(resolve, counter));
}
OR more cumbersome and forceful delay (leads to unpredictable behavior at best and with longer events, the same end result):
function newTimeout(minutes, seconds) {
return new Promise(function(resolve, reject){
let counter = minutes*60+seconds;
let interval = setInterval((() => {
counter--;
if(counter == 0) {
clearInterval(interval);
resolve();
}
}), 1000)
});
};
ALSO tried using just setTimeout to stay away from the setInterval as I understand it is liable to clutter your callstack, ofc the below doesn't change anything now looking at it, but thought I would put it in anyway as I tend to prefer the thought of setTimeout that the function calls itself creating the loop that way.
function start() {
try {
eventList();
} catch (err) {
throw err
} finally {
setTimeout(() => start(), 1000);
}
};
end result is basically:
foo
foo
foo
foo
foo
bar
foo
bar
foo
bar
foo
I need to execute some function but if timeout expired I need to abort this function. I tried to use setTimeout and setImmediate. I wrote this example and used setInterval in callback for checking of working but it did't help me:
function waiter(timeout, fun) {
var functionHandler = setImmediate(fun);
var timeoutHandler = setTimeout(() => {
console.log('stoped');
clearImmediate(functionHandler);
clearTimeout(timeoutHandler);
}, timeout);
fun();
}
waiter(5000, () => {
setInterval(() => {
console.log('work');
}, 500);
});
After clearImmediate and clearTimeout my interval still working. How I understood that method doesn't guarantee that my function will be aborted.
Does anybody have an idea how to abort function execution?
UPDATE:
Yes, I know that I should call clearInterval but it's just an example for work checking. For example I should parse some big data and if it doesn't can do it by timeout I need to cancel this function execution and call something else.
The clearXXX functions don't abort functions that are currently running, they just remove functions from the async queue, so that they never start to run. JavaScript always executes code to its completion. You cannot interrupt code that's running in the main thread.
You need to name your interval
and clear it by its name. So your interval is no longer anonymous, but you've got a reference for it.
let counter = 10;
let newYearCountdown = setInterval( () => {
console.log(counter);
counter--
if (counter === 0) {
console.log("HAPPY NEW YEAR!!");
// here i clear interval by its name.
clearInterval(newYearCountdown);
}
}, 1000);
I was reading one book named 'Hands on node.js' by 'Pedro Teixiera'.
I was trying to execute one same program giving in that book that will call a function and that function is calling the same function recursively within some interval again and again.
But when I executed, it gives only one time '1' and stops
Please help me to figure it out why it is not able to call the same function again.
Sample program is as follows:
var schedule = function(timeout, callbackfunction) {
return {
start: function() {
setTimeout(callbackfunction, timeout)
}
};
};
(function()
{
var timeout = 10000; // 1 second
var count = 0;
schedule(timeout, function doStuff() {
console.log(++ count);
schedule(timeout, doStuff);
}).start(timeout);
})();
You aren't actually calling the function again. start() is the part that starts the timer.
schedule( timeout, function doStuff() {
console.log( ++count );
schedule( timeout, doStuff ).start(); // <--- added .start() here
}).start();
(Also note that the start() function doesn't take parameters.)
with some interval again and again
No, for that you would have used setInterval instead of setTimeout.
it gives only one time '1' and stops
Yes, your doStuff function doesn't put a new timeout. Your odd schedule function needs to be .start()ed!
This function below doesn’t work like I want it to; being a JS novice I can’t figure out why.
I need it to wait 5 seconds before checking whether the newState is -1.
Currently, it doesn’t wait, it just checks straight away.
function stateChange(newState) {
setTimeout('', 5000);
if(newState == -1) {
alert('VIDEO HAS STOPPED');
}
}
Browser
Here's a solution using the new async/await syntax.
Be sure to check browser support as this is a language feature introduced with ECMAScript 6.
Utility function:
const delay = ms => new Promise(res => setTimeout(res, ms));
Usage:
const yourFunction = async () => {
await delay(5000);
console.log("Waited 5s");
await delay(5000);
console.log("Waited an additional 5s");
};
The advantage of this approach is that it makes your code look and behave like synchronous code.
Node.js
Node.js 16 provides a built-in version of setTimeout that is promise-based so we don't have to create our own utility function:
import { setTimeout } from "timers/promises";
const yourFunction = async () => {
await setTimeout(5000);
console.log("Waited 5s");
await setTimeout(5000);
console.log("Waited an additional 5s");
};
⚠️ Just for the record, you might be tempted to use a wait function to circumvent race conditions (when testing asynchronous code for example). This is rarely a good idea.
You have to put your code in the callback function you supply to setTimeout:
function stateChange(newState) {
setTimeout(function () {
if (newState == -1) {
alert('VIDEO HAS STOPPED');
}
}, 5000);
}
Any other code will execute immediately.
You really shouldn't be doing this, the correct use of timeout is the right tool for the OP's problem and any other occasion where you just want to run something after a period of time. Joseph Silber has demonstrated that well in his answer. However, if in some non-production case you really want to hang the main thread for a period of time, this will do it.
function wait(ms){
var start = new Date().getTime();
var end = start;
while(end < start + ms) {
end = new Date().getTime();
}
}
With execution in the form:
console.log('before');
wait(7000); //7 seconds in milliseconds
console.log('after');
I've arrived here because I was building a simple test case for sequencing a mix of asynchronous operations around long-running blocking operations (i.e. expensive DOM manipulation) and this is my simulated blocking operation. It suits that job fine, so I thought I post it for anyone else who arrives here with a similar use case. Even so, it's creating a Date() object in a while loop, which might very overwhelm the GC if it runs long enough. But I can't emphasize enough, this is only suitable for testing, for building any actual functionality you should refer to Joseph Silber's answer.
If you're in an async function you can simply do it in one line:
console.log(1);
await new Promise(resolve => setTimeout(resolve, 3000)); // 3 sec
console.log(2);
FYI, if target is NodeJS you can use this built-in function if you want (it's a predefined promisified setTimeout function):
import { setTimeout } from 'timers/promises';
await setTimeout(3000); // 3 sec
Use a delay function like this:
var delay = ( function() {
var timer = 0;
return function(callback, ms) {
clearTimeout (timer);
timer = setTimeout(callback, ms);
};
})();
Usage:
delay(function(){
// do stuff
}, 5000 ); // end delay
Credits: How to delay the .keyup() handler until the user stops typing?
You should not just try to pause 5 seconds in javascript. It doesn't work that way. You can schedule a function of code to run 5 seconds from now, but you have to put the code that you want to run later into a function and the rest of your code after that function will continue to run immediately.
For example:
function stateChange(newState) {
setTimeout(function(){
if(newState == -1){alert('VIDEO HAS STOPPED');}
}, 5000);
}
But, if you have code like this:
stateChange(-1);
console.log("Hello");
The console.log() statement will run immediately. It will not wait until after the timeout fires in the stateChange() function. You cannot just pause javascript execution for a predetermined amount of time.
Instead, any code that you want to run delays must be inside the setTimeout() callback function (or called from that function).
If you did try to "pause" by looping, then you'd essentially "hang" the Javascript interpreter for a period of time. Because Javascript runs your code in only a single thread, when you're looping nothing else can run (no other event handlers can get called). So, looping waiting for some variable to change will never work because no other code can run to change that variable.
setTimeout(function() {
$('.message').hide();
}, 5000);
This will hide the '.message' div after 5 seconds.
This solution comes from React Native's documentation for a refresh control:
function wait(timeout) {
return new Promise(resolve => {
setTimeout(resolve, timeout);
});
}
To apply this to the OP's question, you could use this function in coordination with await:
await wait(5000);
if (newState == -1) {
alert('Done');
}
Try this:
//the code will execute in 1 3 5 7 9 seconds later
function exec() {
for(var i=0;i<5;i++) {
setTimeout(function() {
console.log(new Date()); //It's you code
},(i+i+1)*1000);
}
}
Best way to create a function like this for wait in milli seconds, this function will wait for milliseconds provided in the argument:
function waitSeconds(iMilliSeconds) {
var counter= 0
, start = new Date().getTime()
, end = 0;
while (counter < iMilliSeconds) {
end = new Date().getTime();
counter = end - start;
}
}
Based on Joseph Silber's answer, I would do it like that, a bit more generic.
You would have your function (let's create one based on the question):
function videoStopped(newState){
if (newState == -1) {
alert('VIDEO HAS STOPPED');
}
}
And you could have a wait function:
function wait(milliseconds, foo, arg){
setTimeout(function () {
foo(arg); // will be executed after the specified time
}, milliseconds);
}
At the end you would have:
wait(5000, videoStopped, newState);
That's a solution, I would rather not use arguments in the wait function (to have only foo(); instead of foo(arg);) but that's for the example.
You can add delay by making small changes to your function ( async and await ).
const addNSecondsDelay = (n) => {
return new Promise(resolve => {
setTimeout(() => {
resolve();
}, n * 1000);
});
}
const asyncFunctionCall = async () {
console.log("stpe-1");
await addNSecondsDelay(5);
console.log("step-2 after 5 seconds delay");
}
asyncFunctionCall();
If you have an asyn function you can do:
await new Promise(resolve => setTimeout(resolve, 5000));
99 times out of 100, this works perfectly:
function a(){
setInterval("b()",1000);
updateText("still working");
}
function b(){
timer++;
updateText(timer);
}
Occasionally the first loop waits for 20 seconds to 2 minutes. Thereafter it runs perfectly. I know the timer can pause on Android phones (when the soft keyboard is shown). Are there other conditions that might delay setInterval?
Firstly, it is strongly advised you provide a callback(function) as the first argument and not a string, because that string is evaluated in the global scope and we all know that bad things happen when we use eval in js (related eval post : When is JavaScript's eval() not evil?).
So, your
setInterval("b()", 1000);
should be rewritten as :
setInterval(b, 1000);
or:
setInterval(function() { b(); }, 1000);
I also recommend you use setTimeout to simulate a setInterval.
The main downfall of the setInterval function is that it executes a block of code every n milliseconds, regardless of the execution of the previous block of code.
So if for some reason a setInterval callback takes longer to execute than the delay provided, it will cause some stack overflows.
Let's take the following code for example :
function foo() {
// this takes about 2 seconds to execute
// .. code here
}
setInterval(foo, 1000);
This will actually freeze the browser because it will execute foo for an (almost) infinite number of times but it will never finish it.
The solution in this kind of case is to emulate the setInterval with setTimeout, in order to ensure that the callback has finished to execute before calling it again:
function foo() {
// this takes about 2 seconds to execute
// .. code here
}
function newSetInterval(callback, duration, callbackArguments) {
callback.apply(this, callbackArguments);
var args = arguments,
scope = this;
setTimeout(function() {
newSetInterval.apply(scope, args);
}, duration);
}
newSetInterval(foo, 1000);
Now, foo is called again only after the previous instance has finished the code execution.
I would apply the same thing to your code, in order to let the browser decide when it can execute the code, and not to force it to execute the block of code weather it's busy at that moment or not:
function a() {
newSetInterval(b, 1000);
updateText("still working");
}
function b() {
timer++;
updateText(timer);
}
function newSetInterval(callback, duration, callbackArguments) {
callback.apply(this, callbackArguments);
var args = arguments,
scope=this;
setTimeout(function() {
newSetInterval.apply(scope, args);
}, duration);
}
If you're interested, I've rewritten the setInterval and clearInterval functions in order to use them anywhere, without taking care of stack overflows :
function setInterval(f, time) {
setInterval.ids = setInterval.ids || {};
setInterval.idCount = setInterval.idCount || 0;
var that = this,
id = setInterval.idCount++,
// to prevent firefox bug that adds an extra element to the arguments
l = arguments.length - 2;
(function theFn() {
// to prevent firefox bug that adds an extra element to the arguments
var args = [].slice.call(arguments, 0, l);
f.apply(this, args);
setInterval.ids[id] = setTimeout.apply(this, [theFn, time].concat(args));
}).apply(that, [].slice.call(arguments, 2, arguments.length));
return id;
}
function clearInterval(id) {
if(!setInterval.ids || !setInterval.ids[id]) {
return false;
}
clearTimeout(setInterval.ids[id]);
return true;
}
try this,
setInterval(b, 1000);
or
setInterval(function(){
timer++;
updateText(timer);
}, 1000);