Как перевести синхронное чтение файла в асинхронный режим для работы в веб-клиенте 1С?

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

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

Почему 1С требует асинхронности?

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

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


&НаКлиенте
Функция ПолучитьТекстИзФайла(п_ПутьКФайлу)
    л_Файл = Новый Файл(п_ПутьКФайлу);
    
    Если НЕ л_Файл.Существует() Тогда
        ОбщегоНазначенияКлиентСервер.СообщитьПользователю("Файл не существует.");
        Возврат Неопределено;
    КонецЕсли;
    
    л_ТекстДок = Новый ТекстовыйДокумент;
    л_ТекстДок.Прочитать(п_ПутьКФайлу);
    Возврат л_ТекстДок.ПолучитьТекст();
КонецФункции

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

Решение 1: Использование механизма ОписаниеОповещения (для версий ниже 8.3.18)

Это классический способ реализации асинхронности через обратные вызовы (callback). Вместо одной функции нам придется создать несколько процедур. Разберем этот процесс по шагам.

Шаг 1. Инициация проверки и чтения.

Вместо использования метода Существует() и Прочитать(), мы вызываем асинхронные аналоги. Основная сложность здесь заключается в том, что результат не возвращается мгновенно. Мы должны передать управление в специальный объект ОписаниеОповещения.

Шаг 2. Передача контекста через ДополнительныеПараметры.

Чтобы данные (например, сам объект текстового документа или путь к файлу) были доступны в следующей процедуре, мы упаковываем их в структуру ДополнительныеПараметры.

Посмотрим на исправленный код:


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

Шаг 3. Обработка результата.

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


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

Решение 2: Современный подход Async/Await (для платформы 8.3.18+)

Если ваша конфигурация работает на актуальных версиях платформы, мы можем избежать дробления кода на множество процедур. Рассмотрим использование ключевых слов Асинх и Ждать. Этот подход позволяет сохранить "линейность" кода, делая его гораздо более читаемым.

Проанализируем пример современной реализации:


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

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

Важные нюансы при работе с асинхронностью

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

Таким образом, переход к асинхронности — это не просто "усложнение кода", а необходимая мера для обеспечения стабильности и кроссплатформенности вашего решения. Использование современных методов Асинх/Ждать делает этот процесс максимально безболезненным для разработчика.

← На главную