【问题标题】:Call function now and every 1 minute on full minute?现在和整分钟每 1 分钟调用一次函数?
【发布时间】:2018-01-17 01:45:28
【问题描述】:

使用计时器,我可以每 1 分钟调用一次函数,但不是我想要的方式,如果现在是 10:35:21,则应该像这样调用函数:

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

如何做到这一点?这是我当前的代码:

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 });

【问题讨论】:

  • 由于其性质,您无法确定何时会在 javascript 中调用某个回调...setTimeout(cb, 1000) 并不真正意味着在 1000 毫秒内调用 cb。这意味着wait for at least 1000ms and then call the callback at your first free slot。 stackoverflow.com/questions/21097421/…
  • 避免这种不准确性如何以最简单的方式做到这一点?
  • 你不能,这就是重点。您不能使用 Javascript 保证这样的时间

标签: javascript angular typescript ionic-framework


【解决方案1】:

我已经更改了 Faisal 的解决方案,现在它可以正常工作了,而且它可以立即启动并且累积偏移量没有问题:

  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        
      }
    });

【讨论】:

  • 这不是 Observables 应该如何工作的,你的 observable 应该只发出感兴趣的数据。如果没有,您必须选择/创建一个过滤器运算符,它返回您需要的可观察对象。
  • 你能告诉我一个应该如何使用 observables 的例子吗?
  • 查看mine,或在订阅前应用包含if 声明的filter operator...
【解决方案2】:

将订阅间隔设置为 1000 并检查秒数何时变为 0。这是一个简单的解决方案,可以通过对原始代码的最小更改来完全按照您的意愿行事:

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.
        }
    }
);

这是一个有效的 plunk:DEMO

【讨论】:

    【解决方案3】:

    你可以从类似的东西开始......

    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();
      })
    ;
    

    【讨论】:

      【解决方案4】:

      尽管如@Hitmands 所说,尝试这样的事情,你永远无法获得完全的精确度:

      let date = new Date(),
          remainingSeconds = 60 - date.getSeconds();
      
      function myFunc () {
        console.log(new Date());
      }
      
      myFunc();
      
      setTimeout(() => {  
        myFunc();
        setInterval(myFunc, 60000);
      }, remainingSeconds * 1000);

      【讨论】:

        【解决方案5】:

        您可以根据到下一分钟的时间量设置超时。

        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()

        【讨论】:

        • 这也是自校正的,因此来自setTimeout 的任何不精确都不会累积到不断漂移的偏移中。
        • 您仍然不能保证它会在 OP 想要的时间准确触发。不精确度不会漂移,但从根本上来说仍然是不精确的,您对此无能为力。
        • @Liam -- 我不认为它适用于实时嵌入式硬件控制器应用程序。虽然这只是我的 5 美分,但很少会考虑偶尔出现几毫秒的不精确,尤其是对于 UI 职责。
        猜你喜欢
        • 2010-11-16
        • 2017-11-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-11-02
        • 1970-01-01
        相关资源
        最近更新 更多