0

Помогите, пожалуйста, разобраться. Я прочитал с десяток вроде бы похожих вопросов тут, но не понимаю, как это применить в своём случае. Есть функция, которая возвращает ближайший рабочий день по такому алгоритму:

function getNextWorkDay (day) { //принимаем день
    let nextDay = addDays(day, 1) //получаем следующий день, который будем проверять
if (!isDayOff(nextDay)) { //если этот день не СБ или ВС, дальше проверяем праздничный ли он
    //(*1)
    isHoliday(nextDay).then(answer => { // isHoliday() возвращает 0 или 1, где 1 - праздничный день
        if (answer === '1') { //если день праздничный -> вызываем функцию заново, она выполнится уже со днём+1
            getNextWorkDay(nextDay)
        }
        else { // если пришло что угодно, кроме "1" (в т. ч. сервис оказался не доступен) считаем день рабочим,
               // выходим из этой функции, попадаем к последнему (*2) return, который вернёт текущий день (nextDay)
            return
        }
    })
}
else { //если день СБ или ВС -> вызываем функцию заново
    getNextWorkDay(nextDay)
}
//если ни в одной из проверок, функция getNextWorkDay не вызвалась заново, то считаем день рабочим и возвращаем его
//(*2)
return nextDay 

}

Но функция завершается (*2) до получения ответа из блока (*1) isHoliday(nextDay).then()". Как заставить последний return (*2) дождаться завершения проверки блока (*1)?

Как в данной логике должна выглядеть реализация? Подход в том, что если день является СБ или ВС, то проверка через сторонний сервис (isHoliday(nextDay)) не производится.

И верно ли то, что раз самая глубокая по вложенности функция (f4) возвращает promise, то все функции вверх по цепочке должны возвращать promise? Иначе код в (f1) выполнится не дождавшись ответа.

f1(){f2()} //получаем массив дней и выводим его на экране
↑
f2(){f3()} //в цикле заполняем массив ближайших рабочих дней
↑
f3(){f4()} //находим следующий не выходной день после переданного
↑
f4() //через fetch проверяем, не выпадает ли праздник на этот день
  • 1
    либо делаете все в коллбеке, который будет вызван после завершения промиса, либо используете await для ожидания результата выполнения прямо в этой точке кода https://learn.javascript.ru/async-await но тогда вся функция должна быть асинхронной и она будет возвращать так же промис – Mike May 26 '22 at 15:47
  • Не могли бы вы объяснить подробнее. То есть в участке (2) должен быть return await какой-то переменной, объявленной в начале функции и изменённой в блоке (1), где isHoliday(nextDay).then()?

    Дело в том, если всю реализацию делать в колбэке isHoliday(nextDay).then(), то функция isHoliday() будет вызываться в любом случае. А она должна вызываться только если функция isDayOff() вернула false.

    – Unicode101 May 26 '22 at 16:15
  • 1
    @Unicode101, для простоты, напиши функцию, представив, что в ней только синхронные функции используются. Когда она заработает. Останется добавить только async в определении и await перед функциями, которые на самом деле синхронные. – Grundy May 26 '22 at 16:26
  • 1
    достаточно написать await isHoliday(nextDay).then(... он в этой точке кода подождет завершения вызова и дальше все пойдет по плану. Но вообще весь код выглядит крайне странно, переменная nextDay устанавливается в значение только в самом начале при объявлении, а последующий код ее ни как не изменяет, так что результат всегда будет одинаков (addDays(day, 1)) – Mike May 26 '22 at 16:37
  • @Mike, логика в том, что функция получает какой-то день и сразу увеличивает его на один, получая "завтра". Если это "завтра" прошло все проверки, то возвращается как результат. Если на каком-то этапе не прошло, то функция вызывает себя рекурсивно, увеличивает день на 1 и снова проводит проверки. Вы считаете это плохим подходом? Как лучше реализовать такой функционал? – Unicode101 May 26 '22 at 16:43
  • 1
    @Mike, просто в очередной раз неверно рекурсия реализована. Не возвращается результат со следующей итерации – Grundy May 26 '22 at 16:43
  • 1
    @Unicode101 функция вызывает себя рекурсивно, увеличивает день на 1 и снова проводит проверки - и результат рекурсивного вызова никуда не сохраняется. – Grundy May 26 '22 at 16:44
  • 1
    @Unicode101 Так и пишите retrun getNextWorkDay(nextDay) или nextDay = getNextWorkDay(nextDay) текущая функция же не заканчивается на том что вызвала себя еще раз и результат то вернет вызывающему все равно самая первая вызыванная. И кстати если делаете функцию асинхронной (что бы использовать await) то ее саму так же надо вызывать с await – Mike May 26 '22 at 16:45
  • 1
    Кстати в рекурсии вообще смысла не вижу, лучше бы циклом сделали бесконечным с return когда результат готов – Mike May 26 '22 at 16:48
  • @Mike, разве не достаточно того, что каждый раз при рекурсивном вызове, функция вызывается с новым параметром? Она вызывается до тех пор, пока не дойдёт до return и тогда этот последний переданный параметр мы получаем как результат выполнения функции – Unicode101 May 26 '22 at 16:58
  • @Unicode101 Нет, как написал выше Grundy, функция то вызывается, но то что она вернула никуда не сохраняется и в первую точку вызова не возвращается. потому что при втором вызове функции у нее будет собственная переменная nextDay – Mike May 26 '22 at 17:06
  • 1
    У вас сейчас фактически написано function x(n) { if(n>3) return n; x(n+1); return n;} вот вызовете такую функцию как x(1) получите 1. А должно быть function x(n) { if(n>3) return n; return x(n+1);} тогда она вернет 4 – Mike May 26 '22 at 17:11

0 Answers0