Как работает асинхронный оператор Ждать в платформе 1С
Содержание
Оператор Ждать в платформе 1С запускает асинхронный код так, будто он синхронный: строка Результат = Ждать ВопросАсинх(...) дожидается ответа пользователя, но интерфейс при этом не замирает. Работает он только внутри процедуры или функции, помеченной словом Асинх, и только на клиенте — в тонком, веб- и мобильном клиенте.
Код на обработчиках оповещения (ОписаниеОповещения) быстро превращается в лапшу из вложенных процедур: показали вопрос — ответ пришёл в другую процедуру, там новый вопрос — снова отдельный обработчик. Ждать убирает эту вложенность: вся логика остаётся в одном методе, сверху вниз.
Ниже — синтаксис, тип Обещание, таймауты диалогов, почему не блокируется поток интерфейса и чем Ждать отличается от обработчика ожидания и фоновых заданий. С последними двумя его путают чаще всего.
Для чего нужен оператор и в какой версии он появился
Ждать, ключевое слово Асинх и тип Обещание появились в версии платформы 8.3.18. Если база работает на платформе с номером ниже 8.3.18, этих средств нет — там доступны только старые модели.
Исторически в 1С сложились три способа работать с операциями, которые не завершаются мгновенно (диалог с пользователем, выбор файла, обращение к серверу):
- 🧱 Синхронные методы —
Вопрос(),Предупреждение(),ВвестиЧисло(). Останавливают выполнение и замораживают интерфейс до ответа. В веб-клиенте по умолчанию запрещены, считаются устаревшими. - 🔁 Обработчики оповещения —
ПоказатьВопрос()и подобные методы с объектомОписаниеОповещения. Результат приходит в отдельную процедуру. Работают везде, но код дробится на куски. - ⚡ Асинхронные методы с
Ждать— методы с суффиксомАсинх(ВопросАсинх,ПредупреждениеАсинх) и ваши собственные асинхронные функции. Пишутся линейно, не морозят интерфейс.
Чтобы разница была наглядной, сравните два подхода к одной задаче — спросить подтверждение и, если согласен, выполнить действие. На обработчике оповещения код разрывается на две процедуры:
&НаКлиенте
Процедура Удалить()
Оповещение = Новый ОписаниеОповещения("ПослеВопроса", ЭтотОбъект);
ПоказатьВопрос(Оповещение, "Удалить строки?", РежимДиалогаВопрос.ДаНет);
КонецПроцедуры
&НаКлиенте
Процедура ПослеВопроса(Результат, Параметры) Экспорт
Если Результат = КодВозвратаДиалога.Да Тогда
УдалитьСтрокиНаСервере();
КонецЕсли;
КонецПроцедуры
С Ждать то же самое умещается в один метод без «прыжка» в отдельную процедуру. Чем больше шагов в сценарии, тем заметнее выигрыш: три вопроса подряд на обработчиках оповещения превращаются в три связанные процедуры, а на Ждать — в три строки одной процедуры.
Ждать — это современная замена первым двум подходам. Новый код имеет смысл писать именно на нём.
Синтаксис: слово Асинх, оператор Ждать и тип Обещание
Процедура или функция, внутри которой вы хотите применить Ждать, обязана начинаться со слова Асинх. Без него компилятор выдаст ошибку ещё при проверке модуля.
&НаКлиенте
Асинх Процедура ПодтвердитьУдаление()
Ответ = Ждать ВопросАсинх(
"Удалить выделенные строки?",
РежимДиалогаВопрос.ДаНет);
Если Ответ = КодВозвратаДиалога.Да Тогда
УдалитьСтрокиНаСервере();
КонецЕсли;
КонецПроцедуры
Как это читается: ВопросАсинх не возвращает ответ сразу — он возвращает Обещание (тип Обещание, по-английски Promise). Оператор Ждать берёт это обещание, приостанавливает процедуру до момента, когда пользователь нажмёт кнопку, и подставляет в переменную Ответ уже готовый результат — значение КодВозвратаДиалога.
Пока процедура «ждёт», она не держит поток интерфейса — платформа возвращает управление в цикл обработки событий. Пользователь может двигать окно, сам диалог отрисовывается нормально.
Любая Асинх-функция снаружи возвращает Обещание, даже если внутри вы пишете обычный Возврат ЗначениеФункции. Поэтому вызывать такую функцию тоже нужно через Ждать:
Асинх Функция ПользовательСогласен()
Ответ = Ждать ВопросАсинх("Продолжить?", РежимДиалогаВопрос.ДаНет);
Возврат (Ответ = КодВозвратаДиалога.Да);
КонецФункции
Асинх Процедура ЗапуститьОбработку()
Если Ждать ПользовательСогласен() Тогда
// ...
КонецЕсли;
КонецПроцедуры
Если применить Ждать к обычному значению, а не к обещанию, оператор просто вернёт это значение. Ошибки не будет, но и смысла в таком вызове нет.
Чего можно дождаться: ответы, файлы и свои функции
«Ожидание событий» в 1С — это ожидание завершения асинхронной операции. Через Ждать удобно дожидаться:
- ответов пользователя в диалогах —
ВопросАсинх,ПредупреждениеАсинх, методы ввода значений с суффиксомАсинх; - операций с файлами на стороне клиента (выбор, помещение файла) — у них тоже есть асинхронные варианты;
- результата ваших собственных
Асинх-функций, которые внутри обращаются к серверу.
Важный момент про «синхронизацию потоков»: встроенный язык 1С на клиенте выполняется в одном потоке. Параллельных нитей, которые нужно синхронизировать мьютексами, здесь нет. Ждать не распараллеливает код — он кооперативно приостанавливает текущий метод и отдаёт управление платформе, пока операция не закончится. Это ближе к очереди событий, чем к многопоточности.
Несколько ожиданий подряд выстраиваются в линейный сценарий без вложенных обработчиков:
Асинх Процедура Мастер()
Имя = Ждать ВвестиСтрокуАсинх("Введите наименование");
Если Имя = Неопределено Тогда
Возврат; // пользователь отменил ввод
КонецЕсли;
Подтверждение = Ждать ВопросАсинх(
"Сохранить «" + Имя + "»?",
РежимДиалогаВопрос.ДаНет);
Если Подтверждение = КодВозвратаДиалога.Да Тогда
СохранитьНаСервере(Имя);
КонецЕсли;
КонецПроцедуры
Отдельный частый сценарий — своя Асинх-функция, которая обращается к серверу и возвращает результат клиенту. Внутри неё серверный вызов остаётся обычным, а наружу функция отдаёт Обещание:
&НаКлиенте
Асинх Функция ЗагрузитьОстатки(Склад)
Данные = ОстаткиСервер(Склад); // вызов серверной функции
Возврат Данные;
КонецФункции
&НаКлиенте
Асинх Процедура ОбновитьТаблицу()
Остатки = Ждать ЗагрузитьОстатки(Склад);
ЗаполнитьТаблицуЗначениями(Остатки);
КонецПроцедуры
Если асинхронная операция завершится ошибкой, исключение возникнет прямо на строке с Ждать. Его можно перехватить привычной конструкцией Попытка … Исключение … КонецПопытки — так же, как для обычного кода:
Попытка
Остатки = Ждать ЗагрузитьОстатки(Склад);
Исключение
ПоказатьПредупреждение(, "Не удалось получить остатки: "
+ ОписаниеОшибки());
Возврат;
КонецПопытки;
Это удобнее разрозненных обработчиков ошибок: весь сценарий и его обработка исключений находятся рядом, в одном методе.
Таймауты диалогов и прерывание ожидания
У диалоговых методов есть параметр таймаута — время в секундах, через которое окно закроется само. Значение 0 означает «ждать без ограничения».
Ответ = Ждать ВопросАсинх(
"Продолжить операцию?",
РежимДиалогаВопрос.ДаНет,
30); // диалог закроется через 30 секунд
По истечении таймаута диалог закрывается автоматически, и возвращённое значение может оказаться Неопределено (пользователь ничего не выбрал). Всегда проверяйте результат перед тем, как его использовать, иначе получите ошибку сравнения или обращения к неопределённому значению.
Отдельного способа «прервать» уже запущенный Ждать в языке нет: операция либо завершается, либо падает с исключением. Если нужна именно отменяемая длительная операция (расчёт на сервере, который пользователь может остановить), это решается не оператором Ждать, а механизмом длительных операций: сервер запускает фоновое задание, клиент периодически опрашивает его состояние и может задание отменить. Сам таймаут диалога к серверному расчёту отношения не имеет — он управляет только временем жизни окна.
Почему интерфейс не зависает и при чём тут фоновые задания
Разница между синхронным и асинхронным вызовом видна сразу. Синхронный Вопрос() останавливает весь клиент: пока открыт диалог, форма не перерисовывается, таймеры не срабатывают. Асинхронный Ждать ВопросАсинх(...) возвращает управление платформе, и интерфейс остаётся живым.
Из-за похожего слова «ждать/фоновый» эти механизмы постоянно смешивают. Разведём их:
| Что это | Где выполняется | Для чего |
|---|---|---|
Ждать / Асинх | клиент, один поток | дождаться диалога, файла, серверного вызова без заморозки формы |
| Фоновое задание | сервер, отдельный процесс | тяжёлый расчёт или длительная обработка данных |
Ждать не выносит вычисления в фон и не ускоряет серверный код. Если внутри Асинх-функции вы вызываете долгую серверную процедуру напрямую, сервер всё равно будет считать столько, сколько нужно, — просто клиент в это время не повиснет наглухо.
Чтобы тяжёлую работу действительно вынести в фон, её запускают фоновым заданием на сервере (в типовых конфигурациях на базе библиотеки стандартных подсистем для этого есть готовый механизм длительных операций), а на клиенте дожидаются результата. Клиентскую обёртку над опросом фонового задания удобно оформить как Асинх-функцию и вызвать её через Ждать — тогда из кода формы это выглядит как одна строка.
Отзывчивый интерфейс — это и риск: пока идёт ожидание, пользователь может нажать ту же кнопку второй раз и запустить операцию повторно. Если действие не должно дублироваться, в начале Асинх-метода ставьте флаг «операция идёт» и блокируйте кнопку, а по завершении снимайте флаг. С синхронным вызовом такой защиты не требовалось, потому что интерфейс был заморожен.
Чем Ждать отличается от обработчика ожидания и других способов
Не каждую задержку решают через Ждать. Есть ещё ПодключитьОбработчикОжидания — таймер формы, который периодически вызывает вашу процедуру. Это разные инструменты.
// запустить опрос каждые 3 секунды
ПодключитьОбработчикОжидания("ПроверитьСостояние", 3);
// остановить, когда больше не нужно
ОтключитьОбработчикОжидания("ПроверитьСостояние");
Процедура-обработчик должна быть клиентской и без параметров. Третий параметр ПодключитьОбработчикОжидания со значением Истина делает срабатывание однократным — удобно для отложенного действия «через N секунд».
Сводка по способам:
| Способ | Блокирует интерфейс | Стиль кода | Когда применять |
|---|---|---|---|
Синхронные методы (Вопрос) | Да | линейный | только в старом коде; в вебе запрещены |
ОписаниеОповещения | Нет | вложенные процедуры | поддержка старого кода |
Ждать / Асинх | Нет | линейный | новый клиентский код с диалогами и вызовами сервера |
ПодключитьОбработчикОжидания | Нет | по таймеру | периодический опрос, отложенный запуск |
Асинх-метод и используйте Ждать — линейно и без заморозки интерфейса.Истина (однократно).ОписаниеОповещения; синхронные методы — только если включён соответствующий режим и база не работает в вебе.Типичные ошибки и отладка
Большинство проблем с Ждать — это несколько повторяющихся ситуаций.
ЖдатьвнеАсинх-метода. Компилятор не пропустит модуль. Пометьте процедуру словомАсинхили уберитеЖдать.- Забыли
Ждатьперед вызовом. Тогда в переменную попадёт сам объектОбещание, а не результат. Сравнение сКодВозвратаДиалога.Давсегда даст ложь, а причину не видно. Проверьте, что перед асинхронным вызовом стоитЖдать. - Попытка применить на сервере. Асинхронная модель — клиентская. В серверном методе
Ждатьне используется; серверный код выполняется синхронно. - Смешение с модальными синхронными вызовами. Нельзя из
Асинх-метода вызывать старый модальныйВопрос()— переведите вызов наВопросАсинх.
При отладке точки останова на строках с Ждать работают штатно. Отладчик проходит по коду сверху вниз, как в синхронном методе, — в этом и ценность линейного стиля. Учитывайте, что в момент Ждать управление уходит платформе: пока открыт диалог, могут отработать другие обработчики формы. Если логика на это не рассчитана, возможны неожиданные пересечения — проверяйте состояние формы после каждого Ждать, а не считайте его «замороженным».
Частые вопросы
С какой версии платформы доступен оператор Ждать?
Ждать, слова Асинх и типа Обещание нет — там работают только обработчики оповещения и синхронные методы.Можно ли использовать Ждать в серверном модуле?
Асинх к серверным методам не применяют.Чем Обещание отличается от результата функции?
Обещание — это объект-«расписка», что результат появится позже. Любая Асинх-функция возвращает именно обещание. Чтобы получить само значение, его разворачивают оператором Ждать.Замораживает ли Ждать интерфейс, как синхронный Вопрос?
Вопрос(), который держит клиент до ответа.Как поймать ошибку асинхронной операции?
Ждать в Попытка … Исключение … КонецПопытки. Если операция завершится неудачно, исключение возникнет на строке с Ждать, и его можно обработать как обычно.Работает ли Ждать в веб-клиенте и на мобильном клиенте?
Можно ли вызвать Асинх-функцию без Ждать?
Обещание, а не результат. Это осмысленно, только если обещание нужно сохранить и развернуть через Ждать позже. В большинстве случаев отсутствие Ждать перед вызовом — ошибка.