簡體   English   中英

JavaScript:如何每隔一小時做某事?

[英]JavaScript: How to do something every full hour?

我想每小時執行一些 JS 代碼。 但是我不能用

setInterval("javascript function",60*60*1000);

因為我想每個小時都做一次,我的意思是在 1:00、2:00、3:00 等等。 我正在考慮類似的事情

var d;
while(true) {
  d = new Date();
  if ((d.getMinutes() == '00') && (d.getSeconds() == '00')){
    // my code here
  }  
}

但它太慢了,而且效果不佳。

謝謝你的任何想法

我會找出現在幾點,弄清楚距離下一個完整小時還有多久,然后等那么久。 所以,

function doSomething() {
    var d = new Date(),
        h = new Date(d.getFullYear(), d.getMonth(), d.getDate(), d.getHours() + 1, 0, 0, 0),
        e = h - d;
    if (e > 100) { // some arbitrary time period
        window.setTimeout(doSomething, e);
    }
    // your code
}

檢查e > 100只是為了確保您不會在 5 ms 之類的東西上執行setTimeout並陷入瘋狂循環。

您可以做的是每分鍾運行一次間隔,並在運行實際代碼之前檢查時間是否為:00

看看這個:

function to_be_executed(){
    ...
    ...
    ...
    makeInterval();
}

function makeInterval(){
    var d = new Date();
    var min = d.getMinutes();
    var sec = d.getSeconds();

    if((min == '00') && (sec == '00'))
        to_be_executed();
    else
        setTimeout(to_be_executed,(60*(60-min)+(60-sec))*1000);
}

高性能和簡短的回答

const runEveryFullHours = (callbackFn) => {
  const Hour = 60 * 60 * 1000;
  const currentDate = new Date();
  const firstCall =  Hour - (currentDate.getMinutes() * 60 + currentDate.getSeconds()) * 1000 - currentDate.getMilliseconds();
  setTimeout(() => {
    callbackFn();
    setInterval(callbackFn, Hour);
  }, firstCall);
};

用法:

runEveryFullHours(() => console.log('Run Every Full Hours.'));

您可以使用類似下面的函數,它很容易適應您的需求。

它計算下一次間隔的時間,然后在每次運行后重新運行腳本(除非您將第三個參數設置為 true)

function runOnInterval(interval_in_ms, function_to_run, only_run_once = false){
    setTimeout(()=>{
        function_to_run();
        if (!only_run_once) runOnInterval(...arguments);
    }, interval_in_ms - ((Date.now() - (new Date().getTimezoneOffset() * 6e4)) % interval_in_ms));
}

示例用法:

// Every day at midnight:
runOnInterval(24 * 60 * 60 * 1000, my_function_to_run);
// Every hour on the hour:
runOnInterval(60 * 60 * 1000, my_function_to_run);
// Every minute on the minute:
runOnInterval(60000, my_function_to_run);
// Every 10 seconds on the 10 second mark:
runOnInterval(1e4, ()=>console.log('this will be run every 10 seconds on the 10 second mark'));

ES6 版本,適用於 NodeJS 和現代瀏覽器 - 根據瀏覽器或服務器時鍾以毫秒為單位執行。

功能:

const doSomething = (something) => {
  let running = true
  let nextHour = () => {
    return 3600000 - new Date().getTime() % 3600000
  }
  let nextCall = setTimeout(() => {
    something()
    doSomething(something)
  }, nextHour())
  return {
    next() { return running ? nextHour() : -1 },
    exec() { something() },
    stop() {
      clearTimeout(nextCall)
      running = false
    },
    start() {
      clearTimeout(nextCall)
      nextCall = setTimeout(() => {
        something()
        doSomething(something)
      }, nextHour())
      running = true
    }
  }
}

用法:

// Do something at next full hour and repeat forever
doSomething(() => console.log('Full hour reached!'))

// Do something every full hour & stop it
let obj = doSomething(() => console.log('Will I ever execute? :/'))
obj.next() // Time to next execution in milliseconds
obj.next() / 1000 // Time to next execution in seconds
obj.next() / 1000 / 60 // Time to next execution in minutes
obj.stop() // Stop executing every full hour
obj.start() // Continue executing every hour
obj.exec() // Execute now

您可以通過每次清除和設置間隔來實現。 這只是第一次,而不是一小時的時間間隔,而是一小時減去當前的分鍾和秒:

var d = new Date();
var secondsPastHour = d.getMinutes()*60 + d.getSeconds();
var intervalId = setInterval( myFn, 60*60*1000 - secondsPastHour*1000 );

function myFn() {
    // do stuff
    // ...
    clearInterval( intervalId );
    intervalId = setInterval( myFn, 60*60*1000 );
}

唯一的問題是它最終可能會開始漂移......解決這個問題的方法是在函數內部做同樣的事情,就像你在啟動它時所做的一樣:

var d = new Date();
var secondsPastHour = d.getMinutes()*60 + d.getSeconds();
var intervalId = setInterval( myFn, 60*60*1000 - secondsPastHour*1000 );

function myFn() {
    // do stuff
    // ...
    clearInterval( intervalId );
    var d = new Date();
    var secondsPastHour = d.getMinutes()*60 + d.getSeconds();
    intervalId = setInterval( myFn, 60*60*1000 - secondsPastHour*1000 );
}

這是每分鍾更新一次的概念證明(我不想等待一個小時來測試我的代碼!): http : //jsfiddle.net/dRsua/

這就是我將如何去做,擴展了之前的答案:

function callEveryFullHour(my_function) {

    var now = new Date();
    var nextHour = new Date(now.getFullYear(), now.getMonth(), now.getDate(), now.getHours() + 1, 0, 0, 0);
    var difference = nextHour - now;

    return window.setTimeout(function(){

        // run it
        my_function();

        // schedule next run
        callEveryFullHour(my_function);

    }, difference);
}

通過這種方式,您可以開始停止任何功能在整小時內運行。

用法:

let my_function = () => { // do something };
let timeout = callEveryHour(my_function);

// my_function will trigger every hour

window.clearTimeout(timeout);

// my_function will no longer trigger on the hour

您需要每分鍾運行一次 setInterval 函數(或每秒運行一次,具體取決於您希望計時器的准確程度)並在分鍾為零時執行您的代碼(順便說一下 get minutes 返回一個介於 0 和 59 之間的數字)。

 function myTimer() {
        var d = new Date()
        if (d.getMinutes() == 0) {
        console.log("full hour");
        }
}

 timer = setInterval(function(){myTimer()},60000)

如果您不想在確定您處於完整小時后每隔一秒/分鍾運行一次間隔,您可以簡單地觸發一個新的每小時間隔並清除初始間隔。

var myHourlyTimer = null;

     function myTimer() {
            var d = new Date()
            if (d.getMinutes() == 0) {
            console.log("full hour");
myHourlyTimer = setInterval(function(){myHourlyTimerFunction()},3600000);
clearInterval(timer)
            }
    }

 timer = setInterval(function(){myTimer()},60000)

也在尋找這個,根據馬克的回應,我寫了這個:

function callEveryFullHour() {

    var now = new Date();
    var nextHour = new Date(now.getFullYear(), now.getMonth(), now.getDate(), now.getHours() + 1, 0, 0, 0);
    var difference = nextHour - now;

    window.setTimeout(function(){

        // code goes here

        console.log("It's a full hour!")
        callEveryFullHour();

    }, difference);

}

對 Steffan 提出的方法提出改進建議,這個方法最適合我。

功能:

 let doSomething = function (interval, task) { let running = false let nextExec = () => { if (interval < 0) interval = 1000 return interval - (new Date().getTime() % interval) } let taskwrapper = () => { //console.log("do more...") task() } let trigger = () => { if (nextCall) clearTimeout(nextCall) if (running) { nextCall = setTimeout(() => { taskwrapper() trigger() }, nextExec()) } } let nextCall = null return { next() { return running ? nextExec() : -1 }, exec() { taskwrapper() }, stop() { if (nextCall) clearTimeout(nextCall) running = false }, start() { if (!running) { running = true if (nextCall) clearTimeout(nextCall) trigger() } } } } /*instantiate an object doSomething(interval, task) */ let obj = doSomething(5000, () => console.log('You go..!')) /*schedule You go...! every 5 seconds */ obj.start() /*stop printing */ //obj.stop() /*execute task once */ obj.exec()

let timerId = null

function wrapper (cb,date = new Date()) {
    if(!date.getMinutes() && !date.getSeconds()){
        setInterval(cb,60*60*1000);
        clearInterval(timerId)
    }
}

timerId = setInterval(wrapper,1000,yourCb)

使用一個包裝函數,該函數將每秒執行一次,直到完整小時到達,然后將調用setInterval(cb,60*60*1000)然后停止執行。

使用 Cron Job 代替純 js 實現是合適的。

var CronJob = require('cron').CronJob;
var job = new CronJob('* * * * * *', function() {
  console.log('You will see this message every second');
}, "@hourly", true, 'America/Los_Angeles');
job.start();

如果此腳本在類 Unix 的服務器上運行,而不是在瀏覽器上運行,那么crontab可能是最好的解決方案,而不是在腳本中按小時制定計划。

https://www.geeksforgeeks.org/crontab-in-linux-with-examples/

一種簡單的方法是不斷運行檢查以檢測小時何時更改:

var lastProcessedHour = -1;

setInterval(function() {
   var d = new Date();
   var currentHour = d.getHours();
   if (currentHour != lastProcessedHour) {
      // do stuff
      console.log("new hour");

      lastProcessedHour = currentHour;
   }
}, 1000);

如果你像上面一樣每秒鍾運行一次,腳本將最遲觸發一秒進入新的一小時。

我認為這種方法既健壯又易於理解,從性能的角度來看,每秒運行一次這個簡單的檢查應該不是問題。

與許多其他人基本相同,但更干凈一些。 其他沒有注意到Date().getTime()在每小時的頂部是 3600000 的整數倍。

fn();          // call this once to exec on the hour

function fn(now) {

   //############## add this to top of your existing fn ###############
   var to_top = 3600000 - new Date().getTime()%3600000;  // msec to top of hour

   clearTimeout(fn.t);                           // in case called out of turn
   fn.t = setTimeout(fn, to_top, true);

   if( !now ) return;
   //###################################################################

   ...fn stuff...
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM