← Назад к вопросам

Что такое повторное использования возвращаемых значений?

2.0 Middle🔥 121 комментариев
#Запросы и оптимизация#Стандарты разработки

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Повторное использование возвращаемых значений в 1С

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

Определение

Это паттерн программирования, который:

  • Вызывает функцию один раз
  • Сохраняет результат в переменную
  • Использует эту переменную вместо повторного вызова
  • Экономит вычислительные ресурсы

Проблема: повторный вызов функций

// ПЛОХО - функция вызывается 3 раза

Процедура РассчитатьЗарплату()
    Если ПолучитьОклад(Сотрудник) > 100000 Тогда
        СообщитьОВысокойЗарплате();
    КонецЕсли;
    
    Налог = ПолучитьОклад(Сотрудник) * 0.13; // вызов 2
    
    СохранитьРеестр(ПолучитьОклад(Сотрудник)); // вызов 3
    // Функция вызвана 3 раза, выполнена 3 раза!
КонецПроцедуры

Решение: кеширование результата

// ХОРОШО - функция вызывается 1 раз

Процедура РассчитатьЗарплату()
    
    // Вызовом функцию один раз и сохранить результат
    Оклад = ПолучитьОклад(Сотрудник);
    
    // Использовать результат
    Если Оклад > 100000 Тогда
        СообщитьОВысокойЗарплате();
    КонецЕсли;
    
    Налог = Оклад * 0.13; // используем переменную
    
    СохранитьРеестр(Оклад); // используем переменную
    // Функция вызвана 1 раз, в памяти только 1 переменная
КонецПроцедуры

Типы возвращаемых значений для кеширования

1. Скалярные значения (числа, строки)

// Функция возвращает одно число
Функция ПолучитьОклад(Сотрудник) Экспорт
    Запрос = Новый Запрос(
        "SELECT Оклад FROM Справочник_Сотрудники WHERE Ссылка = &Сотр"
    );
    Запрос.УстановитьПараметр("Сотр", Сотрудник);
    
    Результат = Запрос.Выполнить();
    
    Если Результат.Пустой() Тогда
        Возврат 0;
    КонецЕсли;
    
    Строка = Результат.Выбрать().Первый();
    Возврат Строка.Оклад;
КонецФункции

// Повторное использование:
Оклад = ПолучитьОклад(Сотрудник); // один вызов
Зарплата = Оклад * 12; // использование из переменной
Налог = Оклад * 0.13; // использование из переменной
Премия = Оклад * 0.5; // использование из переменной

2. Коллекции (массивы, таблицы)

// Функция возвращает таблицу значений
Функция ПолучитьТовары(Категория) Экспорт
    Запрос = Новый Запрос(
        "SELECT * FROM Справочник_Товары WHERE Категория = &Кат"
    );
    Запрос.УстановитьПараметр("Кат", Категория);
    
    ТаблицаТоваров = Запрос.Выполнить().Выгрузить();
    Возврат ТаблицаТоваров;
КонецФункции

// ПЛОХО - функция вызывается 3 раза
Для каждого Товар Из ПолучитьТовары(Категория) Цикл // вызов 1
    Сообщить(Товар.Наименование);
КонецЦикла;

Отчет.Заполнить(ПолучитьТовары(Категория)); // вызов 2

ЗагрузитьВТеблицу(ПолучитьТовары(Категория)); // вызов 3

// ХОРОШО - функция вызывается 1 раз
Товары = ПолучитьТовары(Категория); // один вызов

Для каждого Товар Из Товары Цикл // используем переменную
    Сообщить(Товар.Наименование);
КонецЦикла;

Отчет.Заполнить(Товары); // используем переменную

ЗагрузитьВТеблицу(Товары); // используем переменную

3. Сложные объекты (структуры, соответствия)

// Функция возвращает структуру данных сотрудника
Функция ПолучитьДанныеСотрудника(Сотрудник) Экспорт
    
    ДанныеСотр = Новая Структура();
    
    Запрос = Новый Запрос(
        "SELECT Оклад, Должность, Отдел 
         FROM Справочник_Сотрудники WHERE Ссылка = &Сотр"
    );
    Запрос.УстановитьПараметр("Сотр", Сотрудник);
    
    Результат = Запрос.Выполнить();
    Строка = Результат.Выбрать().Первый();
    
    ДанныеСотр.Вставить("Оклад", Строка.Оклад);
    ДанныеСотр.Вставить("Должность", Строка.Должность);
    ДанныеСотр.Вставить("Отдел", Строка.Отдел);
    
    Возврат ДанныеСотр;
КонецФункции

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

Сообщить(Данные.Должность); // используем поля
РасчитатьНалог(Данные.Оклад);
ПроверитьОтдел(Данные.Отдел);

Примеры из практики

Пример 1: Загрузка параметров

// ПЛОХО:
Процедура ЗаполнитьФорму()
    Если ПолучитьОрганизацию() <> Неопределено Тогда
        Форма.Организация = ПолучитьОрганизацию(); // вызов 1
        Форма.РасчетныйСчет = ПолучитьРасчетныйСчет(ПолучитьОрганизацию()); // вызов 2
        Форма.Банк = ПолучитьБанк(ПолучитьОрганизацию()); // вызов 3
    КонецЕсли;
КонецПроцедуры

// ХОРОШО:
Процедура ЗаполнитьФорму()
    Организация = ПолучитьОрганизацию();
    
    Если Организация <> Неопределено Тогда
        Форма.Организация = Организация;
        Форма.РасчетныйСчет = ПолучитьРасчетныйСчет(Организация);
        Форма.Банк = ПолучитьБанк(Организация);
    КонецЕсли;
КонецПроцедуры

Пример 2: Обработка больших массивов

// Функция дорогостоящая (ищет в большом массиве)
Функция НайтиЭлементВМассиве(Массив, Ключ) Экспорт
    Для каждого Элемент Из Массив Цикл
        Если Элемент.ID = Ключ Тогда
            Возврат Элемент;
        КонецЕсли;
    КонецЦикла;
    Возврат Неопределено;
КонецФункции

// ПЛОХО - поиск выполняется много раз:
Если НайтиЭлементВМассиве(МойМассив, "ID123") <> Неопределено Тогда // поиск 1
    Сообщить("Найдено");
КонецЕсли;

Элемент = НайтиЭлементВМассиве(МойМассив, "ID123"); // поиск 2
Данные.Заполнить(Элемент);

// ХОРОШО - поиск выполняется один раз:
Элемент = НайтиЭлементВМассиве(МойМассив, "ID123"); // один поиск

Если Элемент <> Неопределено Тогда
    Сообщить("Найдено");
КонецЕсли;

Данные.Заполнить(Элемент);

Пример 3: Запросы к БД

// ПЛОХО - запрос выполняется несколько раз:
Если Справочники.Контрагенты.Количество() > 100 Тогда
    Сообщить("Много контрагентов");
КонецЕсли;

ЛистОтправки.ЗаполнитьКонтрагентов(Справочники.Контрагенты.Количество());

// ХОРОШО - вызов один раз:
Количество = Справочники.Контрагенты.Количество();

Если Количество > 100 Тогда
    Сообщить("Много контрагентов");
КонецЕсли;

ЛистОтправки.ЗаполнитьКонтрагентов(Количество);

Оптимизация в циклах

// ОЧЕНЬ ПЛОХО - функция вызывается в каждой итерации:
Для индекс = 1 По 1000 Цикл
    Если НаходитсяВСписке(Справочники.Товары.Получить(индекс), МойСписок) Тогда
        // Обработка
    КонецЕсли;
КонецЦикла;

// ХОРОШО - вызвать один раз до цикла:
Товары = Справочники.Товары.Получить(индекс);

Для индекс = 1 По 1000 Цикл
    Если НаходитсяВСписке(Товары[индекс], МойСписок) Тогда
        // Обработка
    КонецЕсли;
КонецЦикла;

Преимущества

  1. Производительность — уменьшение вызовов дорогостоящих функций
  2. Читаемость — код понятнее (не вложенные вызовы)
  3. Отладка — проще отладить, чем множественные вызовы
  4. Надёжность — одиночное значение не меняется в процессе
  5. Экономия памяти — если результат большой, он в памяти один раз

Минусы неправильного кеширования

// ПЛОХО - кешируем устаревшее значение:

Оклад = ПолучитьОклад(Сотрудник); // получено в начале процедуры

// Где-то в коде изменился оклад
Сотрудник.Оклад = 100000;
Сотрудник.Записать();

// Но мы используем старое значение
ПрименитьНовыйОклад(Оклад); // применяем старое значение!
// Это ошибка!

Чеклист оптимизации

  • Определены дорогостоящие функции
  • Результаты сохраняются в переменные
  • Переменные используются вместо повторных вызовов
  • Кеш не устаревает (проверить логику)
  • Нет повторных вызовов в циклах
  • Память не переполняется (большие массивы)

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