JavaScript:如何每小时做一件事?

JavaScript:如何每小时做一件事?,javascript,time,timer,setinterval,Javascript,Time,Timer,Setinterval,我想每小时执行一些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 } }

我想每小时执行一些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
  }  
}
但是它太慢了,而且不好用


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

我会找出现在是什么时间,计算到下一个完整小时有多长时间,然后等那么长时间。所以

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毫秒左右的时间内执行
setTimeout
,从而陷入疯狂循环。

看看这个:

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

您需要每分钟运行一次setInterval函数(或每秒钟运行一次,具体取决于您希望计时器的准确性),并在分钟数为零时执行代码(顺便说一句,get minutes返回一个介于0和59之间的数字)

如果您不想在确定自己已满一小时后每隔一秒/分钟运行一次时间间隔,只需触发一个新的小时间隔并清除初始时间间隔即可

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)

您可以通过每次清除并设置间隔来完成。这只是第一次,间隔不是一小时,而是一小时减去当前的分和秒:

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

这里有一个每分钟都会更新的概念证明(我不想等一个小时来测试我的代码!):

一个简单的方法是持续运行检查,以检测时间的变化:

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);
如果你像上面那样每秒钟运行一次,脚本最迟会在新的一小时内触发一秒钟


我认为这种方法既健壮又容易理解,从性能的角度来看,每秒运行一次这个简单的检查应该不是什么问题。

也在寻找这个方法,根据Mark的回答,我写了以下内容:

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

}

下面是我将如何进行的,在前面的答案的基础上进行扩展:

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
runEveryFullHours(() => console.log('Run Every Full Hours.'));

您可以使用下面的功能,这很容易适应您的需要

它计算到下一个间隔的时间,然后在每次运行脚本后重新运行脚本(除非将第3个参数设置为true)

用法示例:

// 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版本,适用于NodeJ和现代浏览器-根据浏览器或服务器时钟以毫秒为单位执行

功能:

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
用法:

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

建议改进Steffan提出的方法,这个方法对我最有效

功能:

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
let doSomething=函数(间隔、任务){
让运行=错误
让nextExec=()=>{
如果(间隔<0)间隔=1000
返回间隔-(新建日期().getTime()%interval)
}
让taskwrapper=()=>{
//log(“做更多…”)
任务()
}
让触发器=()=>{
如果(nextCall)清除超时(nextCall)
如果(正在运行){
nextCall=setTimeout(()=>{
taskwrapper()
触发器()
},nextExec())
}
}
设nextCall=null
返回{
下一个(){
返回正在运行的?nextExec():-1
},
行政长官(){
taskwrapper()
},
停止(){
如果(nextCall)清除超时(nextCall)
运行=错误
},
开始(){
如果(!正在运行){
运行=真
如果(nextCall)清除超时(nextCall)
触发器()
}
}
}
}
/*实例化对象doSomething(间隔、任务)*/
让obj=doSomething(5000,()=>console.log('yougo..!'))
/*安排你去。。。!每5秒*/
obj.start()
/*停止打印*/
//对象停止()
/*执行一次任务*/
obj.exec()

使用一个包装器函数,该函数将每秒执行一次,直到整小时结束,然后将调用
setInterval(cb,60*60*1000)
,然后停止执行。

使用Cron作业将适合代替纯js实现

var CronJob=require('cron')。CronJob;
var job=new CronJob('**',function(){
log('您将每秒看到此消息');
}“@hourly”,真的,“America/Los_Angeles”);
job.start();
  • 创建一个作业
  • 计划在服务器上运行它
    • 希罗库-
    • 自动气象站

    如果此脚本在类Unix服务器上运行,而不是在浏览器上运行,那么
    crontab
    可能是比在脚本中每小时制定一次计划更好的解决方案


    高性能&简短回答

    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);
    };
    
    用法:

    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
    
    runEveryFullHours(() => console.log('Run Every Full Hours.'));
    

    “太慢”是个委婉的说法,对吧?这将彻底冻结你的浏览器永远!背景是什么?似乎在服务器上有更好的解决方案,比如Cron作业之类的。。。。但是很难说,不知道它的用途。你需要记住在设置新的间隔之前清除旧的间隔…否则很好。更高的要求/更低的兼容性,并且不包含在一个干净的可调用/命名函数中?