🗽Вызов функции каждый час

skyElmax

Trainee
Привет. В интернете есть эта информация но решил добавить на этот форум для тех кто не умеет пользоваться поиском 😂
К примеру для РП серверов будет актуально вызов PAYDAY каждый час в 00 минут (не обязательно в 00 минут).

JavaScript:
let startScript = (new Date().getHours()+1)%24;//Берем текущий час например 21 прибавляем 1, 21 + 1 = 22 это час когда нужно запустить скрипт
setInterval(timer30sec, 30000);//проверка текущего времени 1 раз в 30 секунд, если нужно чтобы скрипт запускался с точностью до секунды (22:00:00) поставить ~500
function timer30sec(){
    let date = new Date();//Берем текущее время
    if(date.getMinutes() == 0 && date.getHours()==startScript){//Если минут равны нулю и текущий час тому в котором нужно запустить скрипт
           startScript = (startScript+1)%24 ;//прибавляем +1 к часу в котором нужно запустить скрипт
            PayDay();// и запускаем скрипт
    }
}
function PayDay() {
    //Ваш скрипт  
    console.log("Hello, word!");
}

P.S. Код не уникален.
 
Последнее редактирование:

geneff

Junior Developer
Хочу поделится моей реализацией данной функции:
JavaScript:
mp.events.add('packagesLoaded', () => {
    const date = new Date(); // получаем обьект даты
    const minute = 60 - date.getMinutes(); // узнаем сколько  минут осталось до :00
    const senconds = (minute * 60) - date.getSeconds();  // Узнаем сколько секунд осталось до :00
    setTimeout(payDay, minute * 1000); // запускаем таймер с нашим payDay
});

const payDay = () => {
    // наш код, что будет происходит в пейдей
    setTimeout(payDay, 3600 * 1000); // запускаем таймер с интервалом в 1 час
}
 
Последнее редактирование:

Lev Angel

Developer
Команда форума
А я в свое время делал другую реализацию. Запускаю таймер на 1 секунду и сравниваю число минут, секунд, часов и т. д. со значением в предыдущем цикле. Там где не совпадало триггерил событие. Таким образом у меня были события onSecondPass, onMinutePass, onHourPass, вплоть до onYearPass. Таким образом можно было привязывать к ним практически все что угодно (payday, перезагрузку в полночь, поздравление при наступлении нового года :) ) и это все ценой одного таймера.
Правда это было в другом мультиплеере и на другом языке. Так что не смогу им поделиться.
 

geneff

Junior Developer
А я в свое время делал другую реализацию. Запускаю таймер на 1 секунду и сравниваю число минут, секунд, часов и т. д. со значением в предыдущем цикле. Там где не совпадало триггерил событие. Таким образом у меня были события onSecondPass, onMinutePass, onHourPass, вплоть до onYearPass. Таким образом можно было привязывать к ним практически все что угодно (payday, перезагрузку в полночь, поздравление при наступлении нового года :) ) и это все ценой одного таймера.
Правда это было в другом мультиплеере и на другом языке. Так что не смогу им поделиться.
Хех, у меня тоже была похожая система, только в SAMP. Ну как у меня, я ее скопипастил с другого мода, потому что мне понравилась как она реализована :)
А насчёт этого, у меня мысля, что лучше я сделаю один таймер с интервалом в один час, нежели буду каждую секунду проверять время.

Каждому своё, ну и если брать во внимание данный код, то его можно не много переделать:
JavaScript:
setInterval(timer30sec, 30000);//проверка текущего времени 1 раз в 30 секунд, если нужно чтобы скрипт запускался с точностью до секунды (22:00:00) поставить ~500
function timer30sec() {
    const date = new Date();//Берем текущее время
    if(date.getMinutes() === 0 && date.getSeconds() === 0) {//Если минут равны нулю и cекунды равны нулю
        PayDay();// и запускаем скрипт
    }
}
function PayDay() {
    //Ваш скрипт 
    console.log("Hello, word!");
}
 
Последнее редактирование:

Lev Angel

Developer
Команда форума
Твой вариант идеально подходит для payday
 

skyElmax

Trainee
Твой вариант идеально подходит для payday
Серьезно?
Таймеры не точные. Ты можешь поставить таймер на 1 секунду, но он сработает + - 50 мс (это не точно).
В его примере таймер заведен на 30 секунд, если все звезды сошлись в один ряд, то его пэйдэй сработает. Почему?
Опять же, таймеры не точные, и даже если были бы точными то в зависимости от старта сервера, скорее всего пэйдэй сработает только тогда когда сам таймер создастся в 0 секунд текущего времени т.е. это практически не реально.

В моем примере PayDay сработает +- 30 сек... и то не факт.
 

Lev Angel

Developer
Команда форума
Итого имеем проблему с точностью таймеров. Он не гарантирует точность выполнения, чем больше интервал - тем больше будет погрешность. Т. е. интервал задержки это по сути теоретически минимальное время после которого сработает таймер. На самом деле он сработает позже.
Соответственно вариант с таймером на 1 час отпадает, с каждой итерацией он будет уплывать все дальше и дальше.
Решением здесь будет разбить на более короткие интервалы и при каждом вызове таймера корректировать задержку ориентируясь на текущее время. Такой себе таймер с самокоррекцией.
JavaScript:
var start = new Date().getTime(),
    time = 0;

function instance()
{
    time += 100;
    var diff = (new Date().getTime() - start) - time;
    window.setTimeout(instance, (100 - diff));
}

window.setTimeout(instance, 100);

//https://habr.com/ru/post/212889/

При этом если нам нужно вызывать payday раз в час, то может быть имеет смысл делать таймер с переменным интервалом. Т. е. чем ближе к началу часа, тем короче интервалы.
 

geneff

Junior Developer
Ну да, все правильно. Я думал над тем, чтобы добавить это в мой пример, но почему-то не добавил.
Не знаю как JS будет работать с таким кодом, но например в SAMP`e у меня никаких проблем с таймерами не было :unsure:
JavaScript:
mp.events.add('packagesLoaded', () => {
    const date = new Date(); // получаем обьект даты
    const minute = 60 - date.getMinutes(); // узнаем сколько  минут осталось до :00
    const senconds = (minute * 60) - date.getSeconds();  // Узнаем сколько секунд осталось до :00
    setTimeout(payDay, minute * 1000); // запускаем таймер с нашим payDay
});

const payDay = () => {
    const start = new Date().getTime();
    // наш код, что будет происходит в пейдей
    setTimeout(payDay, (3600 * 1000) - (new Date().getTime() - start)); // запускаем таймер с интервалом в (1 час - время выполнения кода)
}

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

Lev Angel

Developer
Команда форума
У тебя new Date().getTime() - start будет всегда равно 0.
 

geneff

Junior Developer
То-есть если у меня будет очень много операций, то он тоже будет равен - 0?
JavaScript:
const payDay = () => {
    const start = new Date().getTime();
    for (let i = 0; i < 1e10; i++) {
        i++;
        i--;
        i *= i;
    }
    setTimeout(payDay, (3600 * 1000) - (new Date().getTime() - start)); // запускаем таймер с интервалом в (1 час - время выполнения кода)
}

UPD: Проверил только что и понял, что ничего не понимаю и правда равно 0 :rolleyes:
 
Последнее редактирование:

Lev Angel

Developer
Команда форума
Сейчас пересмотрел видео про event loop и похоже что величина погрешности не зависит от длинны интервала. Т. е. что 1 минута, что 1 час. Сам таймер отсчитывает время вне основного потока где-то в недрах ноды (могу ошибаться). Но вот за счет того, что выполнение PayDay будет попадать в task queue (где может быть много других задач) или например в основном потоке будет что то сложное обрабатываться, то и будет возникать погрешность.
 

geneff

Junior Developer
А как сделать эту коррекцию, если new Date().getTime() - start = 0 , что же я упускаю?
 

Lev Angel

Developer
Команда форума
JavaScript:
    const start = new Date().getTime();
    // наш код, что будет происходит в пейдей
    setTimeout(payDay, (3600 * 1000) - (new Date().getTime() - start)); // запускаем таймер с интервалом в (1 час - время выполнения кода)
Я не обратил внимания на комментарий, что у тебя между объявлением start и вызовом таймера предполагается код пейдея. Там конечно будет не ноль.
Но ты ведь так компенсируешь только время затраченное на выполнение PayDay, верно? Но у тебя же сама функция PayDay может запуститься на обработку не ровно в 0 минут 0 секунд, а например, через 3 секунды. Поэтому нужно каждый раз корректировать как ты это делаешь в packagesLoaded.
 

skyElmax

Trainee
Вы написали много сообщение по поводу PayDay, скажите пожалуйста, чем так плох мой вариант что вы прибегаете к таким радикальным методам?
 

geneff

Junior Developer
Вы написали много сообщение по поводу PayDay, скажите пожалуйста, чем так плох мой вариант что вы прибегаете к таким радикальным методам?
Не знаю как у других, а у меня нет точного ответа на твой вопрос :ROFLMAO:
Наверное, мы просто хотим показать альтернативные варианты реализации данной системы :unsure:

JavaScript:
mp.events.add('packagesLoaded', () => {
    setTimeout(payDay, secToNextHour() * 1000);
});

const payDay = () => {
    setTimeout(payDay, secToNextHour() * 1000);
}

const secToNextHour = () => {
    const date = new Date();
    return ((60 - date.getMinutes()) * 60) - date.getSeconds();
}
 
Яндекс.Метрика
Верх