Почему асинхронные функции в 1С блокируют интерфейс и как правильно использовать Асинх и Ждать?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

Начиная с версии платформы 8.3.18, в 1С появился новый синтаксис для работы с асинхронными вызовами — ключевые слова Асинх и Ждать. Многие разработчики по аналогии с другими языками программирования предполагают, что простое добавление модификатора Асинх перед функцией и ее вызов на клиенте автоматически переведет выполнение в фон и избавит пользовательский интерфейс от зависаний. Разберем по шагам, почему это не так, и проанализируем, как на самом деле работает этот механизм.

Проанализируем типичную ошибку

Рассмотрим пример кода, в котором разработчик пытается найти "числа Армстронга" с помощью серверной функции, вызывая ее в цикле на клиенте:


&НаСервере
Функция ЧислоАрмстронгаСервер(вхЛимит)
    библиотека = РеквизитФормыВЗначение("Объект");
    возврат библиотека.ЧислоАрмстронга(вхЛимит)
КонецФункции

//Это описание асинхронной функции
&НаКлиенте Асинх
Функция НайтиЧислаАрмстронга(вхЛимит)
    возврат ЧислоАрмстронгаСервер(вхЛимит);
КонецФункции

// Вызывается при нажатии кнопки на форме
&НаКлиенте
Процедура РешитьЗадание(Команда)
    Для i = 2 до 8 цикл
        r = НайтиЧислаАрмстронга(i);
    КонецЦикла;
КонецПроцедуры

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

Даже если обернуть этот вызов в функцию Асинх, платформа просто выполнит синхронный серверный вызов, упакует его результат в специальный объект платформы и вернет на клиент. А поскольку всё это происходит внутри цикла, интерфейс гарантированно "зависнет" до окончания всех итераций.

Разберем механизм: Асинх, Обещание и Ждать

Новый синтаксис 1С является аналогом паттерна async/await, который применяется в C# или JavaScript. Главная цель этого нововведения — избавить разработчиков от сложного и трудночитаемого кода с использованием ОписаниеОповещения ("ада коллбэков"). Теперь асинхронный код выглядит как обычный последовательный. Посмотрим на три главных элемента этого механизма:

  1. Модификатор Асинх: Указывается перед объявлением процедуры или функции. Любая функция с этим модификатором всегда неявно возвращает специальный объект типа Обещание. Само по себе это слово не делает код магическим образом фоновым.
  2. Объект Обещание (Promise): Это своеобразная "обертка" для результата, который еще не получен. Объект может находиться в состояниях ожидания, успешного выполнения или ошибки.
  3. Оператор Ждать: Это ключевой оператор механизма. Он приостанавливает выполнение текущего кода функции, освобождает поток (и клиентский интерфейс) и ждет завершения асинхронной операции. Когда операция завершается, код продолжает выполнение ровно с того же места.

Правильное использование оператора Ждать внутри асинхронной функции выглядит следующим образом:


&НаКлиенте Асинх
Функция НайтиЧислаАрмстронга(вхЛимит)
    ПолучаемоеЧисло = Ждать ЧислоАрмстронгаСервер(вхЛимит); // Здесь интерфейс освобождается до получения ответа
    Возврат ПолучаемоеЧисло;
КонецФункции

Синтаксис Асинх и Ждать предназначен в первую очередь для работы с готовыми асинхронными методами самой платформы 1С. Начиная с 8.3.18, фирма 1С добавила методы-аналоги с суффиксом "Асинх" (например, ВопросАсинх, КопироватьФайлАсинх), которые действительно выполняются асинхронно и не блокируют интерфейс.

Как правильно решить задачу тяжелых вычислений?

Если перед вами стоит задача выполнить тяжелые вычисления на сервере (например, длительные расчеты, поиск простых чисел, обработка больших объемов данных) и при этом сохранить отзывчивость пользовательского интерфейса, механизм Асинх вам не поможет.

Для этих целей по-прежнему необходимо использовать Фоновые задания. Рассмотрим правильный алгоритм действий:

  1. С помощью метода ФоновыеЗадания.Выполнить запустите серверную процедуру в отдельном фоновом потоке.
  2. На клиенте запустите обработчик ожидания (с помощью метода ПодключитьОбработчикОжидания), который будет периодически, например раз в 2 секунды, проверять статус запущенного фонового задания.
  3. Пользователю в это время можно показывать анимацию загрузки или прогресс-бар, интерфейс при этом останется полностью свободным для других действий.
  4. Как только фоновое задание завершится, обработчик ожидания получит результат, отключит сам себя и выведет данные на форму.

Важные нюансы и ограничения

Разберем подробнее некоторые особенности работы с новыми асинхронными методами, о которых важно помнить:

  1. Обработка исключений: Если внутри функции с модификатором Асинх возникает программная ошибка, платформа не выдает привычное окно с красным крестиком немедленно. Ошибка "упаковывается" в возвращаемое Обещание. Чтобы корректно перехватить и обработать такую ошибку, вызов оператора Ждать необходимо оборачивать в конструкцию Попытка ... Исключение.
  2. Ограничения обработчиков событий формы: Не все стандартные события формы поддерживают асинхронность. Например, в событиях ОбработкаВыбора или ПередЗакрытием платформа ожидает мгновенного возврата параметра Отказ. Использование оператора Ждать внутри таких процедур может привести к непредсказуемому поведению системы или прерыванию стандартной цепочки событий. Для таких случаев 1С добавляет новые специализированные события (например, ПередЗакрытиемАсинх).

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

← На главную