n = 0;
var timer = setInterval(function() {
if (n == 0) {
console.log(new Date());
}
// execute some other code here
n++;
if (n == 1000) {
clearInterval(timer);
console.log(new Date());
}
}, 1);
This code executes in about 3-4 seconds, depending on machine and browser maybe. How can I make it execute in exactly 1 second?
Javascript timers in browsers are inaccurate (C would be better for that usage).
However, you get a better averaged accuracy having the delay as high as possible, especially avoiding low values, like 1 ms.
It will be difficult to have 1000 evenly timed calls to a function, within one second. One millisecond being a low value , the simple execution of the triggered function itself (plus the overhead of handling timers) is likely to take a time close to 1 ms (or maybe more)... meaning the JS interpreter calls the function after 1ms, executes the code then set a new 1ms timer. Consequently there is more than 1ms between calls.
The JS interpreter does something like
At t call function <-- this takes
execute function <-- some
at t+x set new 1ms timer <-- time
etc...
However if you can afford to end the process within a timeframe closer to 1 second (than the 3-4 seconds you have now), doing as many as possible 1 ms calls, this is possible.
var n = 0;
var timer= setInterval(function(){
if(n++ == 0) {
console.log(new Date());
}
}, 1);
setTimeout(function() {
clearInterval(timer);
console.log("Got n="+n+" at "+(new Date()));
}, 1000);
This is basically the same program as yours
n is incremented every 1ms
however the end of the process is controlled by another 1-second timer
In Chrome, I get 252 n increments and the two dates are ~1 second apart.
Here is a demonstration of the approach for one timer per iteration. It takes roughly 1 second to do 1000 "iterations" of the same callback. The design is rough as it is only an example.
jsFiddle Demo
//Function to compose the array of timers
function timers(count, callback){
var timers = [];
for(var i = 0; i < count; i++){
timers.push(timer(callback,i));
}
return timers;
};
//Function to compose individual timer
function timer(callback, delay){
return function(){
setTimeout(callback,delay);
};
};
//Usage
console.log("Start:",new Date()); //timestamp
var display = document.querySelector("#display");
var settings = { n : 0 };
display.innerHTML = settings.n;
//Arrange timers and callback
var set = timers(1000,function(){
this.n++;
display.innerHTML = this.n;
if(this.n === 1000) console.log("End:",new Date());
}.bind(settings));
//Execute timers
for(var i = 0; i < set.length; i++){ set[i](); }
<div id="display">
</div>
All browsers handle this differently. In most browsers, especially chrome, the default smallest amount of time possible for a task to execute (as in using an interval or timeout) is 4 milliseconds.
The result of the 4ms window is that your 1000 iterations are being done in about 4 seconds. So, clearly this is longer than the desired 1 second in 1000 iterations.
There is not a desirable (possible?) way to accomplish an exact 1 millisecond iteration in JavaScript when executed in a modern browser. The best bet you would have if space (memory and processing power) were not an issue would be to create a timer for each iteration manually and then execute the entire set of them. This of course has its own issues, such as whether or not each task is even executed at the time it was supposed to.
Try the same script in ECMA Script 6
'use strict';
var n = 0;
var timer = setInterval(() => {
n++;
}, 1);
console.log( new Date() );
setTimeout(() => {
clearInterval(timer);
console.log("Final N Value: "+n+" at "+ (new Date()) );
}, 1000);
Related
var i=0;
function counter(){
for( i;i<100;i++){
setTimeout(()=>{
console.log(i);
},2000)
}
}
counter();
i want to print i in interval of 2 second but it prints immediately
Each call to print takes only a few microseconds. Why? Because it just calls setTimeout. Executing setTimeout takes only a few microseconds to complete. All the call does is schedule something to take place in the future. So within a few microseconds you have scheduled 10 things to take place at about 2 seconds in the future. All the schedulings happen at about the same time. So all the console logs take place at about the same time, two seconds after you scheduled them.
How can i print in interval of 2 second using for loop?
1
2
3
4
... in 2 second delay through for loop
const printNumbersForEvery2Sec = (n) => {
for (let i = 1; i <= n; i++) {
setTimeout(() => {
console.log(i)
}, i * 2000)
}
}
printNumbersForEvery2Sec(10);
Taken from here
Use setInterval(), like this:
var i=0;
var intervalID;
function printAndIncrement()
{
// Stop interval procedure when "var i" reach to 100.
if (i > 100)
{
clearInterval(intervalID);
return;
}
console.log(i);
i++;
}
intervalID = setInterval(printAndIncrement, 1000);
How can i print in interval of 2 second?
'Drift' due to CPU time is a consideration.
If your use case is running code spaced 2 seconds apart minimum, use setTimeout():
let ctr = 1
const fn = () => {
console.log(ctr++)
setTimeout(fn, 2000) // set the next run
}
setTimeout(fn, 2000) // set 1st run
If your use case is running code spaced 2 seconds apart maximum, use setInterval():
let ctr = 1
const fn = () => console.log(ctr++)
setInterval(fn, 2000)
More on JS CPU Timer drift here: https://johnresig.com/blog/how-javascript-timers-work/
Cheers,
function counter(){
for( let i=0;i<100;i++){
setTimeout(()=>{
console.log(i);
},2000)
}
}counter();
Just change var to let
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>
Is there some way to make a function just like the setInterval but the timeout to be exactly the same each time.
In setInterval the timeout varies about the given timeout, a little bit more, a little bit less, but very rare exactly the same.
For example:
var before = new Date().getTime();
setInterval(function() {
var after = new Date().getTime();
newTab.window.location=someURL;
console.log((after - before));
before = after;
}, 50000);
prints 50000,50002, 50005, 50994, 50997, 49999, 50003, 49998 and so on.
I want to be printed always 50000
Javascript is executed in one flow only, so if there is another process doing something at the same time, there's always a chance you timer function will not be executed in time.
If you really need the exact time interval you can block the execution of any other process in advance and hope for the best:
function setExactInterval(handler, time) {
var startTime = Date.now();
setTimeout(function() {
while (true) {
var currentTime = Date.now();
var diff = currentTime - startTime;
if (diff >= time) {
setExactInterval(handler, time);
return handler();
}
}
}, time - 50);
}
It still will not be exact in case the process is blocked by OS though...
Let's say I have a function:
myFunc = function(number) {
console.log("Booyah! "+number);
}
And I want it to run on a set interval. Sounds like I should use setInterval, huh!
But what if I want to run multiple intervals of the same function, all starting at the exact same time?
setInterval(function(){
myFunc(1);
}, 500);
setInterval(function(){
myFunc(2);
}, 1000);
setInterval(function(){
myFunc(3);
}, 2000);
So that the first runs exactly twice in the time it takes the second to run once, and the same between the second and third.
How do you make sure that they all start at the same time so that they are in sync?
Good question, but in JS you can't. To have multiple functions in the same program execute at the same time you need multi-threading and some deep timing and thread handling skills. JS is single threaded. setInterval doesn't acutally run the function after the delay, rather after the delay it adds the function to the event stack to be run as soon as the processor can get to it. If the proc is busy with another operation, it will take longer than the delay period to actually run. Multiple intervals/timeouts are all adding calls to the same event stack, so they run in turn as the proc is available.
function Timer(funct, delayMs, times)
{
if(times==undefined)
{
times=-1;
}
if(delayMs==undefined)
{
delayMs=10;
}
this.funct=funct;
var times=times;
var timesCount=0;
var ticks = (delayMs/10)|0;
var count=0;
Timer.instances.push(this);
this.tick = function()
{
if(count>=ticks)
{
this.funct();
count=0;
if(times>-1)
{
timesCount++;
if(timesCount>=times)
{
this.stop();
}
}
}
count++;
};
this.stop=function()
{
var index = Timer.instances.indexOf(this);
Timer.instances.splice(index, 1);
};
}
Timer.instances=[];
Timer.ontick=function()
{
for(var i in Timer.instances)
{
Timer.instances[i].tick();
}
};
window.setInterval(Timer.ontick, 10);
And to use it:
function onTick()
{
window.alert('test');
}
function onTick2()
{
window.alert('test2');
}
var timer = new Timer(onTick, 2000,-1);
var timer = new Timer(onTick2, 16000,-1);
For a finite number of ticks, change the last parameter to a positive integer for number. I used -1 to indicate continuous running.
Ignore anyone who tells you that you can't. You can make it do just about any thing you like!
You can make something like this.
arr = Array();
arr[0] = "hi";
arr[1] = "bye";
setTimer0 = setInterval(function(id){
console.log(arr[id])
},1000,(0));
setTimer1 = setInterval(function(id){
console.log(arr[id]);
},500,(1));
Hope it helps!
JavaScript is single threaded. You can use html5 web worker or try using setTimeout recursively. Create multiple functions following this example:
var interval = setTimeout(appendDateToBody, 5000);
function appendDateToBody() {
document.body.appendChild(
document.createTextNode(new Date() + " "));
interval = setTimeout(appendDateToBody, 5000);
}
Read this article:
http://weblogs.asp.net/bleroy/archive/2009/05/14/setinterval-is-moderately-evil.aspx
You can use multiples of ticks inside functions, in the example below you can run one function every 0.1 sec, and another every 1 sec.
Obviously, the timing will go wrong if functions require longer times than the intervals you set. You might need to experiment with the values to make them work or tolerate the incorrect timing.
Set a variable to handle tick multiples
let tickDivider = -1
Increase the value of tick variable inside the faster function
const fastFunc = ()=> {
tickDivider += 1
console.log('fastFunciton')
}
Use a condition to on running the slower function
const slowFunc = ()=> {
if (!(tickDivider % 10)){
console.log('slowFunction')
}
}
Call both functions in a single one. The order is not important unless you set tickDivider to 0 (of any multiple of 10)
const updateAllFuncs = () => {
fastFunc()
slowFunc()
}
Set the interval to the frequency of the faster function
setInterval(updateAllFuncs, 100)
What I'm doing here is adding a speed attribute to the HTML elements. These speeds are passed as a parameter to setCounter(). I did this mainly to make the code easier to test and play with.
The function setCounter() is invoked inside a loop for every HTML element with class counter. This function sets a new setInterval in every execution.
The intervals seem to be working in sync.
const elements = document.querySelectorAll('.counter')
elements.forEach((el, i) => {
let speed = Number(elements[i].getAttribute('speed'))
setCounter(el, speed, 5000)
})
function setCounter(element, speed, elapse){
let count = 0
setInterval(() => {
count = (count >= elapse) ? elapse : count + speed
if(count === elapse) clearInterval()
element.innerHTML = count
}, 1)
}
Same Speeds
<p class="counter" speed='10'></p>
<p class="counter" speed='10'></p>
Different Speeds
<p class="counter" speed='3'></p>
<p class="counter" speed='5'></p>
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);
}