4

Using timer I am able to call a function every 1 minute but not the way I want, if now is 10:35:21 the function should be called like this:

at 10:35:21
at 10:36:00
at 10:37:00
at 10:38:00
at 10:39:00
at 10:40:00
etc

How to do this? This is my current code:

let startTime = new Date(Math.ceil(new Date().getTime() / 60000) * 60000);
let source = Rx.Observable.timer(startTime, 60000).timeInterval().pluck('interval');


  this.Subscription = source
    .subscribe(data => { //code });
  • because of its nature, you cannot be sure when a certain callback will be called in javascript... `setTimeout(cb, 1000)` doesn't really mean *call the cb in 1000ms*. It means `wait for at least 1000ms and then call the callback at your first free slot`. https://stackoverflow.com/questions/21097421/what-is-the-reason-javascript-settimeout-is-so-inaccurate#21097655 – Hitmands Aug 09 '17 at 09:13
  • 3
    Possible duplicate of [What is the reason JavaScript setTimeout is so inaccurate?](https://stackoverflow.com/questions/21097421/what-is-the-reason-javascript-settimeout-is-so-inaccurate) – Hitmands Aug 09 '17 at 09:17
  • abstain from this inaccuracy how would one do this in simplest possible way? –  Aug 09 '17 at 09:19
  • You can't, that's the point. You cannot guarantee timings like this using Javascript – Liam Aug 09 '17 at 10:11

5 Answers5

1

You could set a time out based on the amount of time till the next minute.

var ONE_MINUTE_IN_MILLIS = 60000;

var runMe = function() {
  var now = new Date().getTime();
  console.log(new Date());
  setTimeout(runMe, getNextMinute(now));

}


var getNextMinute = function(now) {
  var timePassed = now % ONE_MINUTE_IN_MILLIS;
  return ONE_MINUTE_IN_MILLIS - timePassed;
}

runMe()
Quince
  • 14,790
  • 6
  • 60
  • 69
  • 3
    This is also self-correcting, so any imprecision coming from `setTimeout` won't accumulate into an ever-drifting offset. – John Weisz Aug 09 '17 at 09:29
  • You still can't guarantee that this will fire exactly on the time the OP wants. The imprecision won't drift but it will still be fundamentally imprecise and there is nothing you can do about it. – Liam Aug 09 '17 at 10:13
  • 1
    @Liam -- I don't think it's for a real-time embedded hardware controller application. It's just my 5 cents though, but it's rare that a few milliseconds of occasional imprecision is to be considered, especially for UI duties. – John Weisz Aug 16 '17 at 10:54
0

You can start from something like that...

Rx
  .Observable
  .create((observer) => {
    const oneMin = 60000;
    let index = 0;

    const iterate = () => window.setTimeout(iteration, (
      oneMin - (Date.now() % oneMin)
    ));

    function iteration() {
      observer.next(index++);

      return iterate();
    }

    iteration();
  })
;
Hitmands
  • 13,491
  • 4
  • 34
  • 69
0

Set the subscription interval to 1000 and check when seconds change to 0. Here is a simple solution to do exactly what you want with minimum changes in your original code:

let startTime = new Date(Math.ceil(new Date().getTime() / 60000) * 60000);
let source = Observable.timer(startTime, 1000);
this.Subscription = source.subscribe(
    ticks => {
        if((ticks % 60) === 0) {
            console.log('Current Seconds is 0'); 
            // Perform your action here.
        }
    }
);

Here is a working plunk: DEMO

FAISAL
  • 33,618
  • 10
  • 97
  • 105
0

I have changed Faisal's solution and now it works ok, also it starts instantly and there is no problem with accumulating offset:

  let startTime = new Date();
  this.Source = Rx.Observable.timer(startTime, 1000).timeInterval().pluck('interval');

  this.Subscription = this.Source
    .subscribe(data => {
      if (Math.floor(this.LastPing.getTime() / 60000) * 60000 != Math.floor(new Date().getTime() / 60000) * 60000) {
        this.LastPing = new Date();
        //rest of the code        
      }
    });
  • this is not how Observables should work, your observable should emit only data of interest. If it doesn't, you have to **choose/create** a filter operator which returns the observable you need. – Hitmands Aug 09 '17 at 12:21
  • could you show me an example of how should I use observables? –  Aug 09 '17 at 12:49
  • look at [mine](https://stackoverflow.com/questions/45586102/call-function-now-and-every-1-minute-on-full-minute/45588966#45586882), or apply a `filter operator` containing your `if` statement before your subscription... – Hitmands Aug 09 '17 at 12:52
-1

Try something like this, though, as @Hitmands stated, you'll never get full precision :

let date = new Date(),
    remainingSeconds = 60 - date.getSeconds();

function myFunc () {
  console.log(new Date());
}

myFunc();

setTimeout(() => {  
  myFunc();
  setInterval(myFunc, 60000);
}, remainingSeconds * 1000);
Serge K.
  • 5,303
  • 1
  • 20
  • 27