[英]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.