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

skyElmax

Trainee
Сообщения
19
Привет. В интернете есть эта информация но решил добавить на этот форум для тех кто не умеет пользоваться поиском 😂
К примеру для РП серверов будет актуально вызов 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

Middle Developer
Скриптер
Сообщения
58
Хочу поделится моей реализацией данной функции:
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
Команда форума
Скриптер
Сообщения
795
А я в свое время делал другую реализацию. Запускаю таймер на 1 секунду и сравниваю число минут, секунд, часов и т. д. со значением в предыдущем цикле. Там где не совпадало триггерил событие. Таким образом у меня были события onSecondPass, onMinutePass, onHourPass, вплоть до onYearPass. Таким образом можно было привязывать к ним практически все что угодно (payday, перезагрузку в полночь, поздравление при наступлении нового года :) ) и это все ценой одного таймера.
Правда это было в другом мультиплеере и на другом языке. Так что не смогу им поделиться.
 

geneff

Middle Developer
Скриптер
Сообщения
58
А я в свое время делал другую реализацию. Запускаю таймер на 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
Команда форума
Скриптер
Сообщения
795
Твой вариант идеально подходит для payday
 

skyElmax

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

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

Lev Angel

Developer
Команда форума
Скриптер
Сообщения
795
Итого имеем проблему с точностью таймеров. Он не гарантирует точность выполнения, чем больше интервал - тем больше будет погрешность. Т. е. интервал задержки это по сути теоретически минимальное время после которого сработает таймер. На самом деле он сработает позже.
Соответственно вариант с таймером на 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

Middle Developer
Скриптер
Сообщения
58
Ну да, все правильно. Я думал над тем, чтобы добавить это в мой пример, но почему-то не добавил.
Не знаю как 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
Команда форума
Скриптер
Сообщения
795
У тебя new Date().getTime() - start будет всегда равно 0.
 

geneff

Middle Developer
Скриптер
Сообщения
58
То-есть если у меня будет очень много операций, то он тоже будет равен - 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
Команда форума
Скриптер
Сообщения
795
Сейчас пересмотрел видео про event loop и похоже что величина погрешности не зависит от длинны интервала. Т. е. что 1 минута, что 1 час. Сам таймер отсчитывает время вне основного потока где-то в недрах ноды (могу ошибаться). Но вот за счет того, что выполнение PayDay будет попадать в task queue (где может быть много других задач) или например в основном потоке будет что то сложное обрабатываться, то и будет возникать погрешность.
 

geneff

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

Lev Angel

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

skyElmax

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

geneff

Middle Developer
Скриптер
Сообщения
58
Вы написали много сообщение по поводу 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();
}
 
Верх