Создание асинхронных виджетов

16.10.19

Разработка - Работа с интерфейсом

Описание нескольких способов создания асинхронных виджетов для 1С:Предприятия. Рассматриваются способы с использованием HTTP-сервисов и фоновых заданий.

Прежде чем начать

Сегодня мы создадим простой, но функциональный виджет для 1С:Предприятия, который будет показывать количество активных пользователей в базе. Главной его особенностью будет асинхронное взаимодействие с базой, что позволит выполнять обновление виджета без блокировки основного интерфейса приложения.

 
 Это информация из старого блога DevelPlatform.ru

Хоть материал и был создан в далеком 2015 году, но описанные подходы до сих пор применимы при разработке. Конечно, сейчас уже обновилась работа поля HTML-документа и появились некоторые другие крутые возможности платформы 1С, но это в основном частности. Все предложенные способы создания виджетов не единственные, в конце статьи Вы найдете ссылки на связанные публикации с другими работами коллег.

Виджет

В качестве примера подхода при работе с HTML-виджетами можно продемонстрировать конфигурацию 1С:Документооборот 2.x, где в обработке "Текущие дела" создана форма для отображения различных виджетов с данными о моих задачах, задачах отдела, созданных документах, редактируемых файлов и т.д. Замечательная реализация и в плане функционала, и в плане юзабилити интерфейса, но есть один минус. Обновление виджетов происходит, конечно же, через синхронную контекстную серверную процедуру, что означает передачу на сервер всей формы, получение там данных, перенос их в форму и затем возвращение ее на клиент.

Проще говоря, для обновления виджетов необходимо выполнять синхронный серверный вызов, на время которого выполняется блокировка пользовательского интерфейса. Кто знает, может в новых версиях 1С:Документооборот эта ситуация уже изменилась.

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

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

Мы пойдем другим путем и решим задачу двумя способами:

  • асинхронное обновление виджета с помощью фоновых заданий.
  • асинхронное обновление виджета с помощью AJAX-запросов к HTTP-сервису из поля HTML-документа.

Оба способа имеют плюсы и минусы, которые мы рассмотрим. И так, поехали!

Подготовка

Не буду создавать интригу и сразу покажу результат, который мы добьемся проделав шаги, описанные далее.

Как Вы можете заметить, обновление виджета выполняется автоматически без блокировки пользовательского интерфейса.

На форме виджет добавлен в качестве поля HTML-документа, которое используется и для обновления через фоновые задания, и для обновления с помощью AJAX-запросов. Количество активных пользователей определяется по количеству активных сеансов с помощью следующей функции, расположенной в общем модуле "ВиджетыСервер" (серверный, вызов сервера):

Функция ПолучитьКоличествоАктивныхСеансов() Экспорт
	
	// Получаем количество активных сеансов
	КоличествоАктивныхСеансов = 0;
	Попытка
		ТекущиеСоединения = ПолучитьСеансыИнформационнойБазы();
		КоличествоАктивныхСеансов = ТекущиеСоединения.Количество();
	Исключение
		КоличествоАктивныхСеансов = -1;
	КонецПопытки;
	
	Возврат КоличествоАктивныхСеансов;
	
КонецФункции

Кроме этого в конфигурацию добавлен общий макет "ГлавнаяСтраница" с типом HTML-документ, в котором содержится разметка для виджета, а также скрипты для обновления данных с помощью AJAX-запроса.

 
 Разметка страницы в общем макете

Также добавлена общая форма "ВиджетАктивныеСеансы" с помещенным на нее полем HTML-документа, в которое будет помещаться содержимое виджета. Эта форма добавлена в рабочую область начальной страницы, чтобы при запуске сеанса пользователя виджет сразу же открывался. Ничего особенного в ней нет, только полей HTML-документа (см. выше).

Теперь рассмотрим подробнее каждый из способов.

Фоновые задания

Механизм фоновых заданий предназначен для асинхронного выполнения каких-либо операций. Этот механизм используется повсеместно. В конфигурации "Библиотека стандартных подсистем"реализована подсистема "Длительные операции", предназначенная для запуска каких-либо операций в фоновых заданиях. В свою очередь БСП внедрена практически во все новые конфигурации от фирмы "1С", поэтому использовать ее можно без особых проблем. На Инфостарте можно посмотреть пример использования этой подсистемы.

Мы реализуем собственный функционал по выполнению асинхронных операций в фоновых заданиях, потому что внедрять для демонстрации примером БСП было бы не разумно =). Но для рабочих задач БСП конечно же правильный выбор.

Запуск и отслеживание

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

 
 АсинхронныеВызовы
 
 АсинхронныеВызовыКлиент
 
 АсинхронныеВызовыКлиентГлобальный
 
 АсинхронныеВызовыСервер
 
 ВиджетыСервер

В модуле "АсинхронныеВызовыСервер" находятся процедуры и функции для непосредственного запуска фоновых заданий и проверки их состояний. Все остальные модули реализуют взаимодействие с фоновыми заданиями с клиентской стороны: запуск, проверка состояния, запуск клиентского метода по завершению фонового задания.

Для отслеживания состояния запущенных фоновых заданий в модуль управляемого приложения была добавлена экспортная переменная:

Перем АктивныеАсинхронныеОперации Экспорт;

Переменная инициализируется как массив, куда при запуске операции добавляется объект "Фоновое задание".

При открытии формы виджета выполняется клиентская процедура:

&НаКлиенте
Процедура ОбновитьКоличествоАктивныхСеансовНачало() Экспорт
	
	ТекущаяОперация = АсинхронныеВызовы.ВызватьФункцию(
		// Функция, запускаемая в фоновом задании
		"ВиджетыСервер.ПолучитьКоличествоАктивныхСеансов",
		// Доп. параметры, у нас они не используются
		, 
		// Текущая форма вызова
		ЭтаФорма, 
		// Клиентская экспортная процедура, выполняемая
		// после завершения фонового задания
		"ОбновитьКоличествоАктивныхСеансовНачалоЗавершение");	
	
КонецПроцедуры

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

&НаКлиенте
Процедура ОбновитьКоличествоАктивныхСеансовНачалоЗавершение(АсинхронныйВызов, 
	Состояние, ВозвращенноеЗначение, ОписаниеОшибки) Экспорт
	
	// Если состояние "Завершен", значит фоновое задание отработало без ошибок
	// и вернуло корректное значение. В противном случае оставляем значение
	// по умолчанию
	КоличествоАктивныхСеансов = "---";
	Если Состояние = "Завершен" Тогда
		КоличествоАктивныхСеансов = ВозвращенноеЗначение;
	КонецЕсли;
	
	// Заменяем часть разметки страницы, подставляя туда
	// полученное значение из фонового задания
	НовоеЗначениеТекстаВиджета = ТекстШаблонаВиджета;
	НачалоРазделаСкриптовСтрока = "<!--Раздел скриптов - Начало-->";
	КонецРазделаСкриптовСтрока = "<!--Раздел скриптов - Конец-->";
	НачалоРазделаЗначениеСтрока = "<!--Активные пользователи - Начало-->";
	КонецРазделаЗначениеСтрока = "<!--Активные пользователи - Конец-->";
	
	НачалоРазделаСкриптов = СтрНайти(НовоеЗначениеТекстаВиджета, НачалоРазделаСкриптовСтрока);
	КонецРазделаСкриптов = СтрНайти(НовоеЗначениеТекстаВиджета, КонецРазделаСкриптовСтрока);
	НовоеЗначениеТекстаВиджета = Сред(НовоеЗначениеТекстаВиджета, 1, НачалоРазделаСкриптов-1)
		+ Сред(НовоеЗначениеТекстаВиджета, КонецРазделаСкриптов+СтрДлина(КонецРазделаСкриптовСтрока), СтрДлина(НовоеЗначениеТекстаВиджета)-КонецРазделаСкриптов+1);
		
	НачалоРазделаЗначение = СтрНайти(НовоеЗначениеТекстаВиджета, НачалоРазделаЗначениеСтрока);
	КонецРазделаЗначение = СтрНайти(НовоеЗначениеТекстаВиджета, КонецРазделаЗначениеСтрока);
	НовоеЗначениеТекстаВиджета = Сред(НовоеЗначениеТекстаВиджета, 1, НачалоРазделаЗначение-1) + 
		Строка(КоличествоАктивныхСеансов) 
		+ Сред(НовоеЗначениеТекстаВиджета, КонецРазделаЗначение+СтрДлина(КонецРазделаЗначениеСтрока), СтрДлина(НовоеЗначениеТекстаВиджета)-КонецРазделаЗначение+1);
		
	// Передаем сформированную HTML-разметку в поле HTML-документа на форме
	АктивныеСеансыВиджет = НовоеЗначениеТекстаВиджета;
	
	// Подключаем обработчик ожидания для повторного запуска
	// асинхронной операции
	ПодключитьОбработчикОжидания("ОбновитьКоличествоАктивныхСеансовНачало", 5, Истина);

КонецПроцедуры

Таким образом будет выполняться асинхронный запуск серверной процедуры "ПолучитьКоличествоАктивныхСеансов()", а ее по завершению операции полученное значение передано обратно на клиент.

Плюсы и минусы

 
 Плюсы
 
 Минусы

AJAX

AJAX (Asynchronous Javascript and XML) - подход к построению интерактивных пользовательских интерфейсов веб-приложений, заключающийся в «фоновом» обмене данными браузера с веб-сервером. У нас, конечно, не веб-приложение, но частично применить этот подход все же возможно. Например, в одной из прошлых статей мы уже рассматривали пример создания и использования HTTP-сервиса и там тоже был AJAX.

HTTP-сервис

Основой для работы виджета является HTTP-сервис, возвращающий необходимые данные. Он достаточно простой, никаких сложных алгоритмов и настроек. Для его создания нужно выполнить следующие шаги:

  1. Добавляем HTTP-сервис и настраиваем корневой URL
  2. Создаем шаблон URL
  3. Добавляем GET-метод
  4. Публикуем базу

Листинг обработчика GET-метода приведен ниже:

Функция ActiveUsersget(Запрос)
	
	УстановитьПривилегированныйРежим(Истина);
	
	Ответ = Новый HTTPСервисОтвет(200);
	
	КоличествоАктивныхПользователей = ВиджетыСервер.ПолучитьКоличествоАктивныхСеансов();
	
	// Формируем ответ в формате JSON
	ЗаписьJSON = Новый ЗаписьJSON;
	ЗаписьJSON.ЗаписатьНачалоОбъекта();
	ЗаписьJSON.ЗаписатьИмяСвойства("ActiveUsers");
	ЗаписьJSON.ЗаписатьЗначение(КоличествоАктивныхПользователей);
	ЗаписьJSON.ЗаписатьКонецОбъекта();
	СтрокаJSON = ЗаписьJSON.Закрыть();	
	Ответ.УстановитьТелоИзСтроки(СтрокаJSON, "UTF-8");
	
	Возврат Ответ;
	
КонецФункции

И все! Далее создаем сам виджет.

Поле HTML

Виджет будет представлять собой область, в центре которой число активных сеансов в информационной базе. Во время выполнения асинхронного запроса к HTTP-сервису будет показана дополнительная анимация. Все это реализовано с помощью HTML-разметки, которая будет помещена в поле HTML-документа в форме конфигурации.

Как и в случае с реализацией виджета при помощи фоновых заданий, HTML-разметка виджета хранится в том же общем макете и в момент создания формы помещается в поле HTML-документа. Только теперь получение количества активных пользователей выполняется не фоновым заданием, а при помощи AJAX-запроса самой страницы, направленного ранее созданному к HTTP-сервису.

Вот так выглядит синтаксис AJAX-запроса на странице:

$.ajax({
    crossDomain: true,
    type: "GET",
    contentType: "application/json;charset=utf-8",
    url: "http://localhost/Exp/hs/DevelPlatform/Users",
    dataType: "json",                
    success: function (queryResult) {
        $("#activeUsersValue").text(queryResult.ActiveUsers - 1);                
    },
    error: function (xhr, ajaxOptions, thrownError) {
        $("#activeUsersValue").text("---");
 
    }
});

Для упрощения адрес указан явно и не настраивается. Если это задача для рабочего окружения, то адрес сервиса обязательно нужно задавать параметрами.

HTTP-сервис возвращает нам JSON-объект с единственным свойством "ActiveUsers". В событии "success", при успешном выполнении запроса, извлекается полученное значение и присваивается элементу <p> на веб-странице. При возникновении ошибок в качестве значения будет присвоена строка "---".

Именно эта реализация демонстрируется на анимации раздела "Подготовка" в самом начале статьи.

Плюсы и минусы

 
 Плюсы
 
 Минусы

Выводы

Лучшим вариантом все же является использование фоновых заданий, ведь работа виджетов в тонком и толстом клиенте критична в большинстве случаев. С появлением WebKit использование AJAX в поле HTML-документа становится возможной, поэтому виджеты с его использованием будут очень эффективными и функциональными.

Предложенные варианты не единственные и не всегда могут подойти. Делитесь своим опытом, будет интересно узнать!

А как виджеты делайте Вы?

Другие ссылки

виджет HTTP-сервис асинхронный фоновые задания AJAX

См. также

Богатый редактор картинок, хранимых в базе, с возможностью РИСОВАНИЯ. Редактор внешних файлов картинок. Объект, расширяющий возможности работы с картинками из встроенного языка (Три в одном) + Обработка «Стандартизация картинок»

Работа с интерфейсом Рабочее место Платформа 1С v8.3 Управляемые формы Конфигурации 1cv8 Платные (руб)

Обработка предназначена для редактирования картинок в режиме «Предприятие», с возможностью РИСОВАТЬ на них. Поддерживается работа как в обычных формах (толстый клиент) так и на управляемых формах (тонкий клиент). Обработка позволяет редактировать как картинки, хранимые в базе, так и графические файлы с диска на файловой системе. Помимо базовых функций (изменение размеров, преобразование формата, обрезание картинки, повороты и т.п.) – редактор имеет богатый набор инструментов для рисования. Доступна функция вставки изображения из буфера обмена. Также обработка может быть использована из встроенного языка как объект для редактирования картинок. Объект может быть использован: на стороне клиента, на стороне сервера, из внешнего соединения. Данная обработка будет особенно полезна тем, кто вносит картинки в базу (изображения номенклатуры, фотографии физических лиц и т.п.). Функционал реализуется с использованием JavaScript и бесплатного ПО ImageMagick (без использования внешних компонент).

6000 руб.

16.01.2015    61698    43    59    

80

[Расширения] Динамическое управление видимостью и доступностью элементов форм (УФ) (8.3.6+)

Работа с интерфейсом Платформа 1С v8.3 Управляемые формы Конфигурации 1cv8 Платные (руб)

Механизм «Динамическое управление доступом к элементам форм объектов 1С8» предназначен для обеспечения возможности оперативного управления видимостью и доступностью элементов форм документов и справочников продуктов фирмы «1С» «1С:Предприятие 8». Решение универсальное, встраивается в любую конфигурацию с минимальными доработками, что позволяет без проблем обновлять типовые решения.

5000 руб.

14.01.2016    54313    16    21    

42

Управление дашбордами

Работа с интерфейсом Платформа 1С v8.3 Конфигурации 1cv8 Платные (руб)

Обработка предназначена для создания и управления дашбордами.

2400 руб.

29.06.2020    16623    21    4    

35

Новогоднее оформление для 1С

Работа с интерфейсом Платформа 1С v8.3 1С:Бухгалтерия 3.0 1С:Управление торговлей 11 1С:Зарплата и Управление Персоналом 3.x 1С:Управление нашей фирмой 3.0 Бесплатно (free)

Добавьте новогоднего настроения! Расширение создает декорацию в виде гирлянды на некоторых формах объектов.

27.12.2023    10561    745    elcoan    45    

106

Конструктор HTML, CSS и javascript

Инструментарий разработчика Работа с интерфейсом Платформа 1С v8.3 Конфигурации 1cv8 Абонемент ($m)

Подходит для создания web-страниц для замены управляемых форм 1С, красивых отчетов, интерфейса мобильного приложения на платформе 1С и для простых страниц веб-сайтов.

2 стартмани

10.04.2023    9484    150    acces969    31    

115

Модель состояния для MVC

Работа с интерфейсом Платформа 1С v8.3 Конфигурации 1cv8 Абонемент ($m)

"MVC плохо применима в 1С" - познакомьтесь с моделью состояния и, возможно, ваше мнение поменяется! Представленное решение является эволюционным развитием идеи реализации MVC для 1С. В новой версии добавлены DSL для описания модели состояния, а также параметризация свойств параметров и элементов формы.

1 стартмани

05.07.2022    3577    kalyaka    2    

27

Табло очереди заказов на экран телевизора

WEB-интеграция Работа с интерфейсом Платформа 1С v8.3 1С:Розница 2 Платные (руб)

Связка из веб-приложения и расширения для 1С: Розница 2.3.

3600 руб.

29.04.2022    12009    1    5    

10
Комментарии
В избранное Подписаться на ответы Сортировка: Древо развёрнутое
Свернуть все
1. wowik 884 16.10.19 16:50 Сейчас в теме
+1. А файлов для скачивания не будет?
YPermitin; +1 Ответить
2. пользователь 16.10.19 16:51
(1) демонстрация в виде листингов вроде исчерпывающая.

А так нужно делать какую-то демоконфигурацию, выносить все в настройки, чтобы каждый мог у себя развернуть и так далее. То есть это уже сложнее, и больше будет походить на разработку.
vasiliy_b; acanta; Sedaiko; +3 Ответить
3. пользователь 16.10.19 16:54
(1) планирую выложить другие разработки, среди них есть подобный виджет для 1С:Документооборот в виде расширения. Но сроки пока не назову.
4. belyuchenko.ilia 17.10.19 07:11 Сейчас в теме
Но как это работает в отношении безопасности? Я так понимаю HTTP-форма с аякс запросом будет подключаться к веб-сервису независимо от текущей пользовательской сессии? Т.е. для подключения ей потребуется провести аутентификацию отдельно от клиента? Или в 1С это как-то обыграно?
TigerAdmin; YPermitin; +2 Ответить
5. пользователь 17.10.19 07:16
(4) вопрос с аутентификацией можно решить двумя путями:
1. Использовать BASIC-аутентификацию от 1С. Для этого в Ajax-запросе нужно ее использовать:
beforeSend: function (xhr) {
    xhr.setRequestHeader ("Authorization", "Basic " + btoa(username + ":" + password));
}

При этом пользователь, от имени которого будет подключение к HTTP-сервису, должен обладать минимальными правами в системе 1С.

2. Можно сделать веб-службу не на 1С и для виджетов использовать ее (например WebApi-приложение на .NET Core). Для авторизации использовать токены. Но это может выглядеть намного сложнее, чем реализация в 1С, но со своими преимуществами. В комментариях такое не описать.
6. belyuchenko.ilia 17.10.19 07:46 Сейчас в теме
Я практически не работал с веб-клиентом, отсюда вопросы...
Выходит, что в веб-интерфейсе нет своих встроенных асинхронных интерфейсных элементов?
К тому же веб-клиент вроде бы использует вызовы через апи типа */e1cib/ и там json тоже используется.
Наверняка можно как то оформить функцию так, чтобы ее можно было вызывать асинхронно через этот интерфейс без необходимости делать это через веб-сервис. К тому же это позволило бы обойтись без отдельной аутентификации.
YPermitin; +1 Ответить
7. пользователь 17.10.19 07:53
(6) возможно, но это скользкий путь.

Веб-клиент не подразумевает кастомизацию и "допилки" могут сломаться с выходом новой платформы.
8. vpaoli 26 17.10.19 14:42 Сейчас в теме
Вот эта ссылка
"рассматривали пример создания и использования HTTP-сервиса"

не открывается
YPermitin; +1 Ответить
9. пользователь 17.10.19 14:45
(8) спасибо, что нашли багу.

Исправил. Тут ссылку продублирую: https://infostart.ru/public/1120823/
10. Vortigaunt 96 18.10.19 10:08 Сейчас в теме
Очень интересный подход. Меня интересует, можно ли применить Ajax в платформе 8.2 да еще так, чтобы этот скрипт вызвал внешнее событие, которое отлавливается платформой?
11. 1c-intelligence 12769 18.10.19 20:28 Сейчас в теме
Юрий, а о подходе "Рабочего стола" к решению этой задачи что думаете?
YPermitin; +1 Ответить
14. triviumfan 91 21.10.19 09:46 Сейчас в теме
15. 1c-intelligence 12769 21.10.19 20:15 Сейчас в теме
12. davdykin 25 21.10.19 07:28 Сейчас в теме
Статья конечно отличная, большое спасибо! Хотелось бы конечно какой-то стабильности от платформы, методы работы с Ajax запросами интересны, но отсутсвие стабильности сильно его губит.
YPermitin; +1 Ответить
13. triviumfan 91 21.10.19 09:40 Сейчас в теме
Наконец-то годнота подъехала!
KAV2; YPermitin; +2 Ответить
16. bobank 200 28.05.20 11:39 Сейчас в теме
А зачем усложняться ajax'ом ? Типовой XMLHttpRequest() может проще? И работать будет всегда. И он так же асинхронен.
17. FreeArcher 158 29.05.20 11:37 Сейчас в теме
Вот AJAX же будет работать только если обращение к 1С идет локально, а если по сети на сервер, JS отвергнет кросдоменный запрос. Так ведь?
18. logarifm 1116 29.05.20 19:18 Сейчас в теме
это не чистые асинхронные вызовы, что должно появится в новых версиях платформ я правильно понимаю?

Асинх; Ждать ... Вот этих примеров хотелось бы ;)
19. Tiger77 69 30.05.20 15:12 Сейчас в теме
В варианте AJAX есть еще один минус - съедается еще одна лицензия 1С каждое подключения веб-сервиса.
Оставьте свое сообщение