Javascript-форум (https://javascript.ru/forum/)
-   Общие вопросы Javascript (https://javascript.ru/forum/misc/)
-   -   Рекурсия промисов. Все правильно? (https://javascript.ru/forum/misc/69674-rekursiya-promisov-vse-pravilno.html)

SergeyERjs 11.07.2017 13:23

Рекурсия промисов. Все правильно?
 
Всем привет.
Прошу проверить код.

Было так:
<html>
<head>
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script>
'use strict'
var obj = {count: 0, maxCount: 5};
while (isNeedContinue(obj)) {
	doAnything();
	console.log("Что-то еще...");
}
function doAnything() {
	obj.count++;
	console.log("doAnything", obj.count);
}
function isNeedContinue(obj) {
	console.log("isNeedContinue", obj, obj.count <  obj.maxCount);
	return obj.count <  obj.maxCount
}
</script>
</head>
</html>

Функция doAnything стала асинхронной.
Переделал так:
<html>
<head>
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script>
'use strict'
var obj = {count: 0, maxCount: 5};
*!*$.when((function recursive() {*/!*
	*!*if*/!* (isNeedContinue(obj)) {
		*!*return*/!* doAnything()*!*.then(function () {*/!*
			console.log("Что-то еще...");
			*!*return recursive()*/!*
		})
	}
})())
	.done(function (res) {
		console.log("Done", res);
	})
	.fail(function (err) {
		console.log("Fail", err);
	});
function doAnything() {
	*!*var deferred = $.Deferred();*/!*
	*!*setTimeout(function () {*/!*
		obj.count++;
		console.log("doAnything", obj.count);
		//if (obj.count==3) deferred.reject(new Error("err!"));
		*!*deferred.resolve(obj);*/!*
	*!*}, 1000)*/!*
	*!*return deferred.promise()*/!*
}
function isNeedContinue(obj) {
	console.log("isNeedContinue", obj, obj.count <  obj.maxCount);
	return obj.count <  obj.maxCount
}
</script>
</head>
</html>


Все ли путем?
Технически, все вроде работает. Но вдруг я что-то упустил?
Осваиваю JS, буду благодарен за любую конструктивную критику.

Alexandroppolus 11.07.2017 16:58

дефереды безнадежно устарели. Забудь о них.

лучше юзать нативные промисы. https://jsfiddle.net/jgk0v70f/

SergeyERjs 11.07.2017 17:09

Цитата:

лучше юзать нативные промисы
В IE не работает, а это критично. На babel переходить пока не готов.

За пример спасибо. :)

Alexandroppolus 11.07.2017 18:25

Цитата:

Сообщение от SergeyERjs
В IE не работает, а это критично.

полифилл же есть.
добавь полифилл, и всё заработает. не нужен тут никакой бабель (к счастью).

SergeyERjs 12.07.2017 12:09

Alexandroppolus,
а не подскажете "правильный" полифилл?
Гугл выдает много всего, в т.ч. разные самописные. Есть какой-то стандарт де факто?

Вот этот https://github.com/stefanpenner/es6-promise правильный?

Alexandroppolus 12.07.2017 13:49

https://github.com/petkaantonov/bluebird вроде самый быстрый. Петька Антонов (автор) повёрнут на быстродействии )

SergeyERjs 12.07.2017 14:32

Alexandroppolus,
Спасибо, попробую.

Вот этот тоже вроде неплох https://github.com/lahmatiy/es6-promise-polyfill. Реализует только стандартный функционал, просто подключается, весит 2,6кБ.

SergeyERjs 12.07.2017 20:39

Код, который выполняется после цикла, хочется вынести из функции.
Так будет правильно? Можно ли упростить выделенный фрагмент?
Спасибо.
'use strict'
var obj = {count: 0, maxCount: 5};

function doAnything() {
	return new Promise(function(resolve, reject) {
		setTimeout(function () {
			obj.count++;
			console.log("doAnything", obj.count);
			var testError = false;
			if (testError && obj.count==3) {
				console.log("doAnything Error!");
				reject(new Error("err!"));
			}
			resolve(obj);
		}, 500)
	})
}

function isNeedContinue(obj) {
	console.log("isNeedContinue", obj, obj.count <  obj.maxCount);
	return obj.count <  obj.maxCount
}

*!*
(new Promise(function (resolve, reject) {
	(function _repeat() {
		if (isNeedContinue(obj)) {
			doAnything().then(
				function () {
					console.log("Что-то в цикле...");
					_repeat();
				}, function (error) {
					console.log("Ошибка!");
					reject(error);
				})
		} else {
			console.log("Конец цикла");
			resolve(obj);
		}
	})()
}))
*/!*
	.then(function (res) {
		console.log("Что-то после цикла...", res);
	})
	.catch(function (err) {
		console.log("Fail", err);
		throw err;
	});

SergeyERjs 13.07.2017 00:55

Вынес while в отдельную функцию.
Есть какие-нибудь противопоказания?
Основной код читаемый получился?
'use strict'
var obj = {count: 0, maxCount: 5};

function isNeedContinue(obj) {
	console.log("isNeedContinue", obj, obj.count <  obj.maxCount);
	return obj.count <  obj.maxCount
}

function doAnything() {
	return new Promise(function(resolve, reject) {
		setTimeout(function() {
			obj.count++;
			console.log("doAnything", obj.count);
			var testError = false;
			if (testError && obj.count==3) {
				console.log("doAnything Error!");
				reject(new Error("err!"));
			}
			resolve(obj);
		}, 500)
	})
}

function whilePromise(condition, promise) {
	return new Promise(function(resolve, reject) {
		var _lastResult;
		(function _nextIteration() {
			if (condition()) {
				//console.log("whilePromise. Next iteration.");
				promise().then(function(result) {
					_lastResult = result;
					_nextIteration();
				}, reject);
			} else {
				//console.log("whilePromise. End");
				resolve(_lastResult);
				_lastResult = null;
			}
		})()
	})
}

// Основной код
whilePromise(
	isNeedContinue.bind(null, obj),
	function() {
		return doAnything()
			.then(function() {
				console.log("Что-то еще в цикле...");
				return Promise.resolve(obj);
			}, Promise.reject.bind(Promise))
	}
)
	.then(function(res) {
		console.log("Что-то после цикла...", res);
	})
	.catch(function(err) {
		console.log("Fail");
		throw err;
	});

nerv_ 13.07.2017 09:59

Цитата:

Сообщение от SergeyERjs
Рекурсия промисов.

Прозвучит странно, но я бы не называл это рекурсией. Скорее просто отложенный вызов функции самой себя (привет асинхронность).

У рекурсии есть прямой и обратный ход, глубина.

Сейчас специльно погуглил определении рекурсии, и там прямо так и написано, что рекурсия -- это вызов функции (процедуры) самой себя.
Что ж, могу добавить -- "видимо, только в контексте синхронного исполнения".


Часовой пояс GMT +3, время: 12:17.