Работа с функциями в 1С:Предприятие — основа любой автоматизации, но даже опытные разработчики иногда сталкиваются с неожиданными сложностями при попытке получить их результат. Например, почему функция возвращает Неопределено вместо ожидаемого массива? Или как извлечь данные из структуры, которую вернула процедура? Эта статья разберёт не только стандартные способы получения возвращаемых значений, но и нюансы работы с разными типами данных, включая ДвоичныеДанные, XML и пользовательские объекты.

Мы рассмотрим: базовый синтаксис вызова функций (включая различия между функциями и процедурами), методы обработки результатов в разных контекстах (модули, формы, отчёты), типичные ошибки, из-за которых результат «теряется» или искажается, продвинутые приёмы — например, как получить результат асинхронной функции или работать с промисами в новых версиях платформы.

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

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

1. Разница между функцией и процедурой: почему это важно для результата

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

  • 🔹 Процедура: используется для выполнения действий (например, запись документа, обновление реквизитов). Результат её работы — побочный эффект, а не возвращаемое значение.
    Процедура ЗаписатьДокумент(Док)
    

    Док.Записать();

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

  • 🔹 Функция: всегда возвращает значение через Возврат. Если оператор отсутствует, вернётся Неопределено.
    Функция ПолучитьСуммуДокумента(Док)
    

    Возврат Док.СуммаДокумента;

    КонецФункции

Ключевая ошибка новичков — попытка получить результат от процедуры, как будто это функция. Например, такой код вызовет ошибку:

Сумма = ЗаписатьДокумент(Док); // Ошибка! Процедура не возвращает значение

В то же время, если функция не содержит Возврат, она вернёт Неопределено, что часто остаётся незамеченным и приводит к логическим ошибкам в алгоритмах.

📊 Какой тип возвращаемого значения вы используете чаще?
Простые типы (Число, Строка)
Структуры и массивы
Объекты 1С (Документ, Справочник)
Двоичные данные/XML

2. Базовые способы получения результата функции

Самый простой способ — присвоить результат функции переменной или использовать его напрямую в выражении. Рассмотрим основные варианты:

  • 📌 Присваивание переменной:
    Перем Результат;
    

    Результат = ПолучитьСуммуДокумента(ТекущийДокумент);

    Здесь Результат будет содержать значение, возвращённое функцией ПолучитьСуммуДокумента.

  • 📌 Использование в выражениях:
    Если ПолучитьСтатусДокумента(Док) = "Проведён" Тогда
    

    // Действия для проведённого документа

    КонецЕсли;

    Функция вызывается прямо в условии Если.

  • 📌 Передача результата в другую функцию:
    ОтправитьНаПечать(ПолучитьДанныеДляПечати(Док));

    Результат одной функции становится аргументом другой.

Например, такой код вызовет ошибку:

Сообщить(ПолучитьСумму(Док) + ПолучитьСумму(Док) * 0.2); // Функция вызывается дважды!

Лучше сначала сохранить результат в переменную, а затем использовать её.

☑️ Проверка перед использованием результата функции

Выполнено: 0 / 4

3. Работа с сложными типами данных: структуры, массивы, объекты

Функции в могут возвращать не только простые типы (число, строка, дата), но и сложные структуры. Рассмотрим, как с ними работать:

Тип данных Пример возврата Как получить результат
Массив
Возврат Новый Массив(1, 2, 3);
Элемент = Результат[0]; // Первый элемент
Структура
Возврат Новый Структура("Сумма,Количество", 1000, 5);
Сумма = Результат.Сумма;
Таблица значений
Возврат ТаблицаДанных;
Строка = Результат.Найти(ИскомоеЗначение);
Объект 1С (Документ, Справочник)
Возврат Документ.СоздатьДокумент();
НовыйДок = Результат;

НовыйДок.Дата = ТекущаяДата();

Особое внимание требуют динамические структуры, когда состав полей заранее неизвестен. В этом случае удобно использовать метод Свойство():

Значение = Результат.Свойство("ДинамическоеПоле", Неопределено);

Если поле отсутствует, вернётся Неопределено (или значение по умолчанию, если указано).

Что делать, если функция возвращает Неопределено?

Причин может быть несколько:

1. В функции отсутствует оператор Возврат.

2. Ошибка в логике функции (например, не найдены данные).

3. Функция выполняется в другом контексте (например, на сервере), и результат не передан клиенту.

Для диагностики добавьте в функцию отладочный вывод: Сообщить("Функция выполнена, результат: " + Результат);

4. Получение результата из серверных функций на клиенте

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

// Некорректный код:

Результат = ПолучитьДанныеСервер(); // Функция выполняется на сервере

Сообщить(Результат); // На клиенте результат может быть недоступен!

Проблема в том, что серверный контекст и клиентский — разные. Чтобы передать результат с сервера на клиент, нужно явно указать это в объявлении функции:

  • 🔧 Серверная функция с возвратом клиенту:
    &НаСервере
    

    Функция ПолучитьДанныеСервер() Экспорт

    Возврат "Данные с сервера";

    КонецФункции

    Ключевое слово Экспорт делает функцию доступной для вызова с клиента.

  • 🔧 Вызов с клиента:
    Результат = ПолучитьДанныеСервер(); // Теперь работает!

Если функция выполняется на сервере без Экспорт, клиент не получит результат. Также Например, объекты (документы, справочники) передаются по ссылке, а не копируются.

💡

Чтобы избежать ошибок при передаче данных между сервером и клиентом, используйте простые типы (Число, Строка, Дата) или сериализуемые структуры. Например, вместо передачи объекта ДокументОбъект лучше вернуть его Ссылку или УникальныйИдентификатор

5. Обработка ошибок и исключений при получении результата

Даже если функция написана корректно, при её выполнении могут возникать ошибки, из-за которых результат не будет получен. Рассмотрим, как обрабатывать такие ситуации:

  • ⚠️ Проверка на Неопределено:
    Результат = ПолучитьДанные();
    

    Если Результат = Неопределено Тогда

    Сообщить("Функция не вернула результат!");

    КонецЕсли;

  • ⚠️ Использование Попытка.Исключение:
    Попытка
    

    Результат = ВыполнитьОпаснуюОперацию();

    Исключение

    Сообщить("Ошибка: " + ОписаниеОшибки());

    Результат = Неопределено;

    КонецПопытки;

  • ⚠️ Проверка типа результата:
    Если ТипЗнч(Результат) <> Тип("Число") Тогда
    

    Сообщить("Функция вернула нечисловое значение!");

    КонецЕсли;

Особенно важно обрабатывать ошибки при работе с внешними источниками данных (например, веб-сервисами или файлами). Например, функция загрузки данных из XML может вернуть ошибку, если файл повреждён:

Функция ЗагрузитьXML(ПутьКФайлу)

Попытка

Возврат ЗагрузитьДанныеИзXML(ПутьКФайлу);

Исключение

ЗаписатьЖурналРегистрации("Ошибка загрузки XML: " + ОписаниеОшибки());

Возврат Неопределено;

КонецПопытки;

КонецФункции

💡

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

6. Продвинутые техники: асинхронные функции и промиссы

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

  • 🚀 Объявление асинхронной функции:
    Асинх Функция ПолучитьДанныеИзAPI()
    

    Возврат Ожидание АсинхОперация.Выполнить();

    КонецФункции

  • 🚀 Обработка результата с помощью Тогда:
    ПолучитьДанныеИзAPI().Тогда(Функция(Результат)
    

    Сообщить("Данные получены: " + Результат);

    КонецФункции);

  • 🚀 Обработка ошибок с помощью Иначе:
    ПолучитьДанныеИзAPI().
    

    Тогда(Функция(Результат) Сообщить(Результат)).

    Иначе(Функция(Ошибка) Сообщить("Ошибка: " + Ошибка.Описание));

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

  • 🌐 Обращения к внешним API (например, получение курсов валют из ЦБ).
  • 📂 Работы с файлами большого размера.
  • 🔄 Длительных расчётов, которые не должны блокировать интерфейс.

Например, такой код не сработает:

Результат = ПолучитьДанныеИзAPI(); // Результат будет Промис, а не фактические данные!

Сообщить(Результат); // Выведет объект Промис, а не данные

💡

Для отладки асинхронного кода используйте метод Ждать() в тестовых сценариях, но не забывайте убирать его в продакшн-коде, чтобы не блокировать выполнение.

7. Типичные ошибки и как их избежать

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

⚠️ Внимание: Если функция объявлена как Экспорт, но не содержит Возврат, клиентский код получит Неопределено, но ошибки не будет. Это может привести к трудновыявляемым багам.
  • 🐞 Игнорирование контекста выполнения:

    Функция, написанная для выполнения на сервере, не будет работать на клиенте (и наоборот). Всегда проверяйте директивы &НаСервере, &НаКлиенте.

  • 🐞 Несоответствие типов:

    Если функция должна возвращать Число, но возвращает Строку, это может привести к ошибкам в расчётах. Используйте ТипЗнч() для проверки.

  • 🐞 Потеря результата при асинхронном выполнении:

    Забыв обработать Промис с помощью Тогда(), вы не получите фактический результат.

  • 🐞 Изменение объекта после возврата:

    Если функция возвращает объект (например, ДокументОбъект), его изменение после возврата может привести к неожиданным последствиям. Лучше возвращать копию или ссылку.

Чтобы избежать ошибок, следуйте простым правилам:

  1. Всегда документируйте, какой тип данных возвращает функция.
  2. Используйте Экспорт только там, где это необходимо.
  3. Тестируйте функции в разных контекстах (сервер/клиент).
  4. Для сложных функций пишите модульные тесты.

Часто задаваемые вопросы

Как получить результат функции, если она возвращает таблицу значений?

Результат функции, возвращающей ТаблицаЗначений, можно обработать стандартными методами работы с таблицами. Например:

Таблица = ПолучитьТаблицуДанных();

Для Каждого Строка Из Таблица Цикл

Сообщить(Строка.Наименование);

КонецЦикла;

Если таблица большая, используйте методы Найти() или Получить() для поиска конкретных строк.

Почему функция возвращает Неопределено, хотя в коде есть оператор Возврат?

Причин может быть несколько:

  1. Оператор Возврат находится внутри блока Если, который не выполнился.
  2. Функция завершилась с ошибкой до оператора Возврат.
  3. Функция выполняется в другом контексте (например, на сервере), и результат не передан клиенту.

Добавьте отладочный вывод перед Возврат, чтобы проверить, достигается ли этот оператор.

Можно ли вернуть из функции несколько значений?

Прямо возвращать несколько значений нельзя, но есть обходные пути:

  • Вернуть Структуру с несколькими полями.
  • Вернуть Массив.
  • Использовать выходные параметры (но это характерно для процедур, а не функций).

Пример со структурой:

Функция ПолучитьДанные()

Возврат Новый Структура("Сумма,Количество,Дата", 1000, 5, ТекущаяДата());

КонецФункции

Результат = ПолучитьДанные();

Сумма = Результат.Сумма;

Как передать результат функции в отчёт или обработку?

Если функция возвращает данные для отчёта, их можно передать несколькими способами:

  1. Через параметры отчёта (если функция вызывается при формировании).
  2. Через глобальные переменные или общие модули.
  3. Через временное хранилище (ПоместитьВоВременноеХранилище()).

Пример с временным хранилищем:

// В функции:

Адрес = ПоместитьВоВременноеХранилище(Данные);

Возврат Адрес;

// В отчёте:

Данные = ПолучитьИзВременногоХранилища(Адрес);

Что делать, если функция выполняется слишком долго и результат не успевает вернуться?

Для длительных операций используйте:

  • Асинхронные функции (для 1С 8.3.20+).
  • Фоновые задания (ФоновыеЗадания.Выполнить()).
  • Разбиение задачи на более мелкие этапы.

Пример с фоновым заданием:

АдресРезультата = ФоновыеЗадания.Выполнить("ДлительнаяОперация", Параметры);

// Позже можно получить результат по адресу