Серверные вызовы, которые нельзя вызывать
Не баян, а классика. Рассмотрим особенность платформы настолько же древнюю, как сами УФ.
Встречали ли такое? Создаёшь себе событие у таблицы формы. Никого не трогаешь.
А тут бац - нельзя создать процедуру на сервере. Неожиданно
Почему? Можно, конечно, почитать в Синтаксис Помощнике… Но зачем? Опять, небось, платформа косячит! Поэтому часто разработчики пытаются её перехитрить:
Выбирают создание “на сервере без контекста” и удаляют текст “БезКонтекста”
Платформа не ругается, проверки синтаксиса проходят. Profit!!!
В действительности же, так делать не есть хорошо и может привести к неожиданным последствиям. Вплоть до падения платформы.
Обратимся всё же к Синтаксис Помощнику:
Как видим, сразу пишут о том, что так делать нельзя.
Более того:
В обработчике данного события нельзя использовать серверные методы формы с директивой компиляции &НаСервере, а также изменять свойства, которые могут привести к серверному вызову
Что это значит? Что в ПриАктивацииСтроки()
нельзя изменять Заголовок
, Доступность
, Подсказку
и т.д. Проверить это легко:
Так а почему? Самый быстрый пример:
Изменение заголовка колонки приводит к обращению к серверу. На этой гифке можно лицезреть результат - бесконечный цикл платформы:
Как это работает? Событие ПриАктивацииСтроки
изменяет свойство, которое выполняет обращение к серверу, что снова вызывает событие ПриАктивизацииСтроки. И так до бесконечности (или же до падения платформы).
А вот ещё одно интересное поведение. Допустим, в ПриАктивацииСтроки()
код выпал в ошибку:
Если это произойдёт в клиентском методе, то всё хорошо. Пользователь закроет окошко с ошибкой и продолжит работать:
То же произойдёт в методе НаСервереБезКонтекста
Но стоит применить директиву &НаСервере, как будет интересное поведение.
Теперь ошибка будет повторяться бесконечно. И ничего, кроме завершения работы сеанса, не поможет пользователю избавиться от неё.
Вот такая незадача.
Но проблема не только в ПриАктивацииСтроки()
. Есть и другие методы, например, ПередНачаломИзменения()
. В каждом из таких методов будет описан соответствующий комментарий в Синтаксис Помощнике. Что будет, если нарушить его указания?
Вот такое поведение нам удалось поймать на “продуктиве”.
Суть кода: ПередНачаломИзменения()
код обращается на сервер, делает запрос и получает строку, которую нужно присвоить в свойство поля формы ПодсказкаВвода
.
Мы же для примера приведем упрощенную реализацию без запроса.
В нашей тестовой обработке ПередНачаломИзменения()
у нас срабатывает процедура:
Далее: в обработке имеется ОбязательнаяКолонка
. И, если её не заполнить, произойдёт такое:
Ничего не обычного, всё работает. Но! Если вдруг пользователь откроет обработку и, не кликая на таблицу, нажмёт на кнопку проверки, то произойдёт падение с записью дампа:
Такое необычное поведение встретилось у нас на работе в продуктивной базе в форме документа. Представляете, как были недовольны пользователи, которые периодически натыкались на падающую от записи документа платформу?)
Всякие необычные проблемы могут возникать в самых неожиданных местах. И что же с этим делать, если наткнулись на такое? Как исправить свою формочку, чтобы она не приводила пользователей в бешенство?
1. Не обращаемся к серверу
Часто разработчики делают то, что им не нужно (или так, как нет нужды). Далеко не всегда нужно обращаться на сервер. И далеко не всегда нужно производить действия, которые к этому приведут. Можно пересмотреть код в таких событиях. Например, в нашей ситуации с бесконечным изменением заголовка группы формы, можно воспользоваться свойством ПутьКДаннымЗаголовка
.
Для этого добавляем строковый реквизит:
А в свойствах группы указываем его:
А в коде меняем не заголовок группы, а значение строкового реквизита:
Кстати, такой подход сам по себе является оптимизацией в ситуациях, когда у группы часто меняется заголовок и работает быстрее, чем менять через свойство.
2. Используем &НаСервереБезКонтекста
Чаще всего обращения к серверу в подобных событиях можно сделать &НаСервереБезКонтекста. Просто далеко не всегда разработчик задумывается об этом заранее. Нужны данные формы в методе? Можно их передать. Чаще всего этого достаточно, главное - не лениться.
3. Запоминаем обработанную строку
Если уж нет никаких вариантов и нам нужно обязательно выполнить именно серверный метод, то можно попробовать просто запомнить последнюю обработанную строку и игнорировать попытки сделать это повторно. Вот пример реализации:
Добавляет числовой реквизит формы (или общую переменную формы ТекущаяСтрока
). И дорабатываем наш метод:
4. Обработчик ожидания
Можно использовать обработчик ожидания. Например, в ПриАктивацииСтроки() не выполнять серверный код напрямую, а выполнять одноразовое выполнение обработчика ожидания, в котором уже происходят нужные действия.
Однако, как показывает практика, не во всех ситуациях использование обработчика ожидания позволяет избежать зацикливания. Поэтому, лучше всего этот метод использовать вместе с проверкой на повторную обработку строки. А ещё лучше комбинировать все методы, чтобы добиться наиболее оптимального результата.
Выводы
При разработке, старайтесь внимательно читать СП\ИТС и следовать рекомендациям. Можно, конечно, следовать принципу “главное работает”. А в какой-то момент столкнуться с неожиданным поведением платформы. Потому что, в описанных нами примерах, ошибки могут вылезти в самый неожиданный момент. И уже на продуктиве =)
P.S.: А вообще, раз уж описан такой запрет в СП, то почему бы не сделать его на уровне проверки синтаксиса платформы?