简体   繁体   English

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

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

I want to execute some JS code every hour.我想每小时执行一些 JS 代码。 But I can't use但是我不能用

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

because I want to do it every full hour, I mean in 1:00, in 2:00, in 3:00 and so on.因为我想每个小时都做一次,我的意思是在 1:00、2:00、3:00 等等。 I am thinking about something like我正在考虑类似的事情

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

but it's too slow and it doesn't work well.但它太慢了,而且效果不佳。

Thak you for any ideas谢谢你的任何想法

I would find out what time it is now, figure out how long it is until the next full hour, then wait that long.我会找出现在几点,弄清楚距离下一个完整小时还有多久,然后等那么久。 So,所以,

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
}

The check for e > 100 is just to make sure you don't do setTimeout on something like 5 ms and get in a crazy loop.检查e > 100只是为了确保您不会在 5 ms 之类的东西上执行setTimeout并陷入疯狂循环。

您可以做的是每分钟运行一次间隔,并在运行实际代码之前检查时间是否为:00

look at this one :看看这个:

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

High performance & Short answer :高性能和简短的回答

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

Usage:用法:

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

You could use something like the function below, which is very easy to adapt to your needs.您可以使用类似下面的函数,它很容易适应您的需求。

It calculates how long until the next interval, and will then re-run the script after it has been run each time (unless you set the 3rd argument to true) .它计算下一次间隔的时间,然后在每次运行后重新运行脚本(除非您将第三个参数设置为 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));
}

Example Usage:示例用法:

// 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 version, works in NodeJS and modern browsers - executes on millisecond according to browser or server clock. ES6 版本,适用于 NodeJS 和现代浏览器 - 根据浏览器或服务器时钟以毫秒为单位执行。

Function:功能:

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

Usage:用法:

// 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

You could do it by clearing and setting the interval each time.您可以通过每次清除和设置间隔来实现。 It's just that first time, instead of the interval being one hour, it would be one hour minus the current minutes and seconds:这只是第一次,而不是一小时的时间间隔,而是一小时减去当前的分钟和秒:

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

The only problem with this is that eventually it will probably start drifting...the solution to that would be to just do the same thing inside the function as you do when kicking it off:唯一的问题是它最终可能会开始漂移......解决这个问题的方法是在函数内部做同样的事情,就像你在启动它时所做的一样:

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

Here's a proof of concept that updates every minute (I didn't want to wait a whole hour to test my code!): http://jsfiddle.net/dRsua/这是每分钟更新一次的概念证明(我不想等待一个小时来测试我的代码!): http : //jsfiddle.net/dRsua/

This is how I would go about it, expanding on the previous answer:这就是我将如何去做,扩展了之前的答案:

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

This way you can start stop any function from running on the full hour.通过这种方式,您可以开始停止任何功能在整小时内运行。

Usage:用法:

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

You need to run a setInterval function every minute (or every second depending on how accurate you want your timer to be) and execute your code when minutes are zero (btw get minutes returns a number between 0 and 59)..您需要每分钟运行一次 setInterval 函数(或每秒运行一次,具体取决于您希望计时器的准确程度)并在分钟为零时执行您的代码(顺便说一下 get minutes 返回一个介于 0 和 59 之间的数字)。

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

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

If you do not want to have an interval running every second/minute after you established that you are on full hour you can simply trigger a new hourly interval and clear the initial one.如果您不想在确定您处于完整小时后每隔一秒/分钟运行一次间隔,您可以简单地触发一个新的每小时间隔并清除初始间隔。

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)

Was also looking for this, based on Mark's response, I wrotethis:也在寻找这个,根据马克的回应,我写了这个:

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

}

Proposing improvement to the approach proposed by Steffan, this one worked best for me.对 Steffan 提出的方法提出改进建议,这个方法最适合我。

Function:功能:

 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)

use a wrapper function that will get executed every second till the full hour has arrived and then will call setInterval(cb,60*60*1000) and then will stop executing.使用一个包装函数,该函数将每秒执行一次,直到完整小时到达,然后将调用setInterval(cb,60*60*1000)然后停止执行。

Using Cron Job would be suitable instead of pure js implementation.使用 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();

If this script is running at a Unix-like server, not a browser, then crontab might be the best solution than making the schedule hourly in the script.如果此脚本在类 Unix 的服务器上运行,而不是在浏览器上运行,那么crontab可能是最好的解决方案,而不是在脚本中按小时制定计划。

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

One simple way would be to continously run a check to detect when the hour changes:一种简单的方法是不断运行检查以检测小时何时更改:

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

If you run it every second like above the script will trigger one second into the new hour at the latest.如果你像上面一样每秒钟运行一次,脚本将最迟触发一秒进入新的一小时。

I think this method is both robust and easy to understand, and from a performance standpoint it should't really be an issue to run this simple check once every second.我认为这种方法既健壮又易于理解,从性能的角度来看,每秒运行一次这个简单的检查应该不是问题。

Basically the same as many others, but a little cleaner.与许多其他人基本相同,但更干净一些。 Other fail to note that Date().getTime() is integer multiple of 3600000 on the top of every hour.其他没有注意到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