TGStat
TGStat
Введите текст для поиска
Расширенный поиск каналов
  • flag Russian
    Язык сайта
    flag Russian flag English flag Uzbek
  • Вход на сайт
  • Каталог
    Каталог каналов и чатов Региональные подборки Тематические подборки Платные каналы Поиск каналов
    Добавить канал/чат
  • Рейтинги
    Рейтинг каналов Рейтинг чатов Рейтинг публикаций
    Рейтинги брендов и персон
  • Аналитика
  • Поиск по публикациям
  • Мониторинг Telegram
  • Продвижение
    Реклама через Яндекс Бизнес Реклама в каналах через TGStat Agency Реклама на сайте TGStat.ru
Настя Котова // Frontend & Node.js

14 Sep, 18:31

Открыть в Telegram Поделиться Пожаловаться

В прошлый раз разбирали, зачем нужны using и await using и где они работают. Теперь посмотрим, во что этот синтаксис разворачивается.

Если очень грубо, то блок с объявлениями превращается в try/finally, где в finally вызываются собранные методы очистки. Но интересно не это, а детали, которые спрятаны в спецификации.

Самое неочевидное: метод очистки берётся у объекта в момент объявления, а не при выходе из блока. Рантайм сразу достаёт [Symbol.dispose], запоминает ссылку на функцию и кладёт её во внутренний стек области. Поэтому подмена метода после объявления ни на что не влияет.


const res = { Symbol.dispose { console.log('первый'); } };
{
using r = res;
res[Symbol.dispose] = () => console.log('второй');
} // первый


Оттуда же следует и то, что если у объекта нет нужного метода, TypeError прилетит сразу на строке объявления. При этом null и undefined тоже разрешены, чтобы можно было писать необязательные ресурсы без проверок.

Теперь немного про await using. Слово await здесь относится к невидимому в коде вызову Symbol.asyncDispose при выходе из области. Поэтому в строке await using file = await open(path) два await: второй ждёт открытия файла сейчас, первый — его закрытия потом.

Если у объекта есть только синхронный Symbol.dispose, await using возьмёт его. Однако обычный using на объекте с асинхронной очисткой бросит ошибку.

Самый тонкий момент — что будет, если исключение бросит и тело блока, и сама очистка. Обе ошибки сохраняются в обёртке нового типа — SuppressedError.


try {
using r = { Symbol.dispose { throw new Error('ошибка очистки'); } };
throw new Error('ошибка тела');
} catch (e) {
e.error; // ошибка очистки
e.suppressed; // ошибка тела
}


В error лежит та, что пришла последней и вытеснила предыдущую, а в suppressed — та, которую вытеснили. Если ресурсов несколько и падают они по очереди, получается цепочка вложенных SuppressedError, по которой можно дойти до самой первой.

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

1k 0 6 24 15
Каталог
Каталог каналов и чатов Подборки каналов Поиск каналов Добавить канал/чат
Рейтинги
Рейтинг каналов Telegram Рейтинг чатов Telegram Рейтинг публикаций Рейтинги брендов и персон
API
API статистики API поиска публикаций API Callback
Наши каналы
@TGStat @TGStat_Chat @telepulse @TGStatAPI
Почитать
Академия TGStat Исследование Telegram 2019 Исследование Telegram 2021 Исследование Telegram 2023
Контакты
Справочный центр Поддержка Почта Вакансии
Всякая всячина
Пользовательское соглашение Политика конфиденциальности Публичная оферта
Наши боты
@TGStat_Bot @SearcheeBot @TGAlertsBot @tg_analytics_bot @TGStatChatBot