Точно выполнять функцию, когда изменяется минута?

Как я могу точно запустить функцию, когда изменяется минута? Использование setInterval может работать, если я запускаю его правильно, когда изменяется минута. Но я беспокоюсь, что setInterval может быть прерван циклом событий в длительном процессе и не оставаться в синхронизации с часами.

Как я могу точно выполнить функцию при изменении минуты?

Ответ 1

Во-первых, вы должны использовать setInterval для повторения таймеров, поскольку он (пытается) гарантировать периодическое выполнение, то есть любые потенциальные задержки будут не складываются, как они будут с повторяющимися вызовами setTimeout. Это будет выполнять вашу функцию каждую минуту:

var ONE_MINUTE = 60 * 1000;

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

setInterval(showTime, ONE_MINUTE);

Теперь нам нужно сделать это в нужное время:

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 an even interval
    setTimeout(start, delay);
}

repeatEvery(showTime, ONE_MINUTE);

Ответ 2

Это может быть идея. Максимальное отклонение должно составлять 1 секунду. Если вы хотите, чтобы это было более точно, уменьшите миллисекунды setTimeout 1.

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 Но, см. также этот вопрос, о точности тайм-аутов в javascript

Ответ 3

Вы можете попытаться быть настолько точными, насколько сможете, установив тайм-аут каждые X миллисекунд и проверить, прошла ли минута и сколько времени прошло с момента последнего вызова функции, но об этом.

Вы не можете быть на 100% уверены, что ваша функция будет срабатывать ровно через 1 минуту, потому что там может быть что-то, блокирующее цикл событий.

Если это что-то жизненно важное, я предлагаю использовать для этого специальный cronjob или отдельный процесс Node.js(так что вы можете убедиться, что цикл событий не заблокирован).

Ресурсы

http://www.sitepoint.com/creating-accurate-timers-in-javascript/

Ответ 4

Я предложил вам возможное решение:

/* 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();

};

Ниже приведен пример использования, который печатает метку времени каждую минуту, но временный дрейф корректируется каждую секунду

coolerInterval(function() {

    console.log( new Date().getTime() );

}, 1000, 60);

Это не идеально, но должно быть достаточно надежным. Учтите, что пользователь может переключить вкладку в браузере, или ваш код может иметь некоторые другие блокирующие задачи, запущенные на странице, поэтому решение для браузера никогда не будет идеальным, это зависит от вас (и ваших требований), чтобы решить, достаточно ли он достаточно или нет.

Ответ 5

Моя первая мысль заключалась в использовании объекта Date, чтобы получить текущее время. Это позволит вам установить заданный интервал в минуту с помощью простой математики. Затем, поскольку вы беспокоитесь о том, что вы выходите, каждые 5-10 минут или что-то, что вы считаете подходящим, вы можете перепроверить время, используя новый объект даты, и соответственно отрегулировать свой интервал.

Это только моя первая мысль, хотя утром я могу выложить какой-то код (например, здесь 2am).

Ответ 6

Протестировано в браузере и node.js

  • спит до 2 секунд до минутной смены, затем ждет перемены
  • вы можете удалить ведение журнала, так как это становится довольно загроможденным в журнале, в противном случае

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

Ответ 7

Это довольно простое решение... интервал времени ожидания корректируется каждый раз, когда он вызывается, чтобы он не дрейфовал, с небольшой безопасностью 50 мс на случай, если он сработает рано.

function onTheMinute(callback) {
    const remaining = 60000 - (Date.now() % 60000);
    setTimeout(() => {
        callback.call(null);
        onTheMinute(callback);
    }, remaining + (remaining < 50 ? 60000 : 0));
}