@Anarmus

Возможна ли рекурсия в js через setTimeout?

В качестве наркомании пишу функцию:
function userFadeout2(el, delay, opacity) {
	delay = typeof delay !== 'undefined' ?  delay : 50;

	if(el.style.opacity == "") {
		el.style.opacity = 1;
		opacity = el.style.opacity;
	}
	else if(typeof opacity !== 'undefined') {
		el.style.opacity = opacity;
	}
	else {
		opacity = el.style.opacity;
	}
	
	if(opacity == 0) {
		el.style.display = 'none';
		console.log('конец');
		return true;
	}
	else {
		setTimeout(function() {
			opacity -= 0.1;
			console.log(opacity);
			return userFadeout2(el,delay,opacity.toFixed(1));
		},delay);
	}
}

Первая реализация
function userFadeout(el, delay) {
	if(el.style.opacity == "") {
		el.style.opacity = 1;
	}
	if(el.style.opacity == 0) {
		el.style.display = 'none';
		return true;
	}
	else if((el.style.opacity -= 0.1) == 0) {
		el.style.display = 'none';
		console.log('конец');
		return true;
	}
	else {
		if(typeof delay != 'undefined' || delay == '') {
			setTimeout(userFadeout, delay, el, delay);
		}
		else {
			console.log(el.style.opacity);
			setTimeout(userFadeout, 50, el);
		}
	}
}

Кучу промежуточных и производных реализация публиковать пожалуй не буду... Логика, я надеюсь и так понятна.

Проблема в том, что функция возвращает 'undefined' при первом же вызове, после чего не возвращает больше ничего, хотя после выполнения и завершения в консоль пишется 'конец'.
Эксперимент показывает, что если убрать setTimeout, то функция возвращает true и завершается там где и задумывается (после проверки на opacity == 0), в последней итерации.

Прогуглив никакого решения не нашёл, суть проблемы казалось бы понял, но потом понял, что ничего не понял. Не совсем понятно происходит ли вообще рекурсия (судя по всему нет), или просто вызывается "новая" функция, а "старая" завершается. В таком случае не понятно почему все остальные функции не возвращают ничего...
Кто может подсказать, в чём глубинная ошибка и непонимание? Или с setTimeout рекурсия вообще не возможна? И в какую сторону вообще смотреть и что читать?

Консоль-логи функции
undefined
0.9
0.8
0.7000000000000001
0.6
0.5
0.4
0.30000000000000004
0.19999999999999998
0.1
0
конец

  • Вопрос задан
  • 315 просмотров
Пригласить эксперта
Ответы на вопрос 4
delphinpro
@delphinpro Куратор тега JavaScript
frontend developer
Выбросив всё лишнее
if(opacity == 0) {
    ...
    return true;
} else {
  ...
}


видим, что если opacity не равен нулю, то ничего не возвращается.

Лень вникать, но, скорее всего вы не учли что это —
return userFadeout2(el,delay,opacity.toFixed(1));
возврат из анонимной функции-параметра setTimeout, а не вашей рекурсивной функции.
Ответ написан
@kttotto
пофиг на чем писать
Все правильно, он и будет возвращать undefined. Я думаю, что Вы не верно трактуете выполнение setTimout(). Вот в этом участке
else {
    setTimeout(function() {
      opacity -= 0.1;
      console.log(opacity);
      return userFadeout2(el,delay,opacity.toFixed(1));
    },delay);
  }

не будет ожидания выполнения setTimeout, он создаст отложенное выполнение и вернет undefined, т.к. другого ничего не указано. Дальше setTimeout запустит Вашу функцию userFadeout2, но она так же, если opacity будет не равно 0, вернет undefined.
Лень проверять, но кажется setTimeout возвращает delay и Ваш return userFadeout2 не сработает как Вы хотите. Вам нужно сделать что-то подобие
else {
	$.when(setTimeout(function() {
		  console.log("pause");
		},delay)
	).then(function(){
		opacity -= 0.1;
		console.log(opacity);
		userFadeout2(el,delay,opacity.toFixed(1));
	});
}

Это без проверок с ходу, как пример, думаю мысль уловите.
Ответ написан
alex_keysi
@alex_keysi
Помог с решением? Отметь “правильный ответ”
Функция будет возвращать только true. Где ты тестируешь функцию в devtool? Тебе консоль выводит правильно. Твоя функция возвращает undefined на первом вызове. Это когда ты в консоли запустил в первый раз функцию.
Потом консоль тебе выводит консоль логи. На второй и т д. итерациях консоль уже не будет выводить undefined.
Видимо ты ее тестишь в консоли разработчика
Поэтому такие консоли логи. Твоя функция нигде не делает return opacity.
То что ты выложил это ты проверял в консоли?
Ответ написан
Комментировать
@Coder321
Примерно так
function userFadeout2(el, delay, opacity) {
    return new Promise((resolve, reject) => {
        delay = typeof delay !== 'undefined' ? delay : 50;

        if (el.style.opacity == "") {
            el.style.opacity = 1;
            opacity = el.style.opacity;
        }
        else if (typeof opacity !== 'undefined') {
            el.style.opacity = opacity;
        }
        else {
            opacity = el.style.opacity;
        }

        if (opacity == 0) {
            el.style.display = 'none';
            console.log('конец');
            return resolve(true)
        }
        else {
            setTimeout(function () {
                opacity -= 0.1;
                console.log(opacity);
                return resolve(userFadeout2(el, delay, opacity.toFixed(1)));
            }, delay);
        }
    })
}
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы