dependencies, предотвращение рекурсивного вызова.

Если "повесить" зависимость некоторого атрибута на колонку, в методе-обработчике зависимости изменять значение колонки-зависимости - вполне предсказуемо получить рекурсивный вызов.
Но обычно цепочка рекурсивных вызовов пресекается установкой флага, или внедрением проверок, которые гарантированно не пройдут при повторном вызове, что в свою очередь обеспечит выполнение рекурсивного вызова без изменения целевого значения.
В данном случае, не зависимо от механики предусмотренной в методе-обработчике, его вызов уходит в рекурсию в том случае если во время его исполнения было изменено значение зависимой колонки.
н/п

attributes: {
...
        "SameHandler": {
                dependencies: [
                        {
                                //поле с типом "Дата-время"
                                columns: ["TargetColumn"],
                                methodName: "SameHandlerControl"
                        }
                ]
        },
...

methods: {
...
                "SameHandlerControl": function() {
                        if (window.foo) {
                                window.foo = false;
                        } else {
                                window.foo = true;
                                this.set("TargetColumn", new Date());
                        }
                },

так вот несмотря на то, что при повторном вызове обработчика, выполнение уходит в ветку
...
                        if (window.foo) {
                                window.foo = false;
...

после чего, рекурсивные вызовы, по идее, должны закончиться т.к. значение "TargetColumn" более не меняется, по факту вызовы SameHandlerControl уходят в бесконечную рекурсию

Как этого избежать ?
Почему так происходит ?

PS: классический кейс "самоконтроля поля ввода" - поле реагирует на изменение своего значения вызовом обработчика, который производит проверки и вычисления с введенным значением, по необходимости корректируя/восстанавливая свое собственное значение, предотвращая рекурсивный вызов обработчика.

Нравится

2 комментария

Здравствуйте
Интересный случай. Глубоко не копал, но причина вроде бы в последовательности вызова
меняя this.set("TargetColumn", new Date());, вы "дергаете" SameHandlerControl, т.к. атрибут связан с колонкой. И поскольку перед "самовызовом" метода вы меняете флаг выхода, то получается замкнутый цикл

попробуйте вызвать window.foo = true; ПОСЛЕ this.set("TargetColumn", new Date());

мой тестовый код, на котором нет вечного цикла

define("UsrSection1Page", [], function() {
	return {
		entitySchemaName: "UsrSection",
		attributes: {
			"SameHandler": {
				dependencies: [
					{
						columns: ["UsrName"],
						methodName: "SameHandlerControl"
					}
				]
			}
		},
		methods: {
			"SameHandlerControl": function() {
				var n = this.get("UsrName");
				if (window.foo) {
					window.foo = false;
				} else {
					//window.foo = true;
					this.set("UsrName", n + window.foo);
					window.foo = true;
				}
			}
		},
...

Я решил, проблему "отложенным вызовом на 100 мс." смены атрибута который приводит к вызову обработчика в рекурсии

...
setTimeout(function(){
     this.set("TargetColumn", new Date())
}.bind(this), 100);
...

т.е. как только выполнение обработчика завершается корректно - повторный вызов из отложенной функции уже корректно ловит "флаг" и его обрабатывает.

PS:
создается такое впечатление что срабатывание обработчиков - псевдосинхронное, т.е. this.set банально "стакает" текущий контекст, и функция вызывается повторно, не завершившись в предыдущий раз.

Показать все комментарии