using
Базовый уровень Ограниченная доступность
Эта функция не является базовой, поскольку она не работает в некоторых из наиболее широко используемых браузеров.
Объявление using объявляет локальные переменные с областью видимости блока, которые синхронно высвобождаются. Как и const, переменные, объявленные с помощью using, должны быть инициализированы и не могут быть переназначены. Значение переменной должно быть либо null, либо undefined, либо объектом с методом [Symbol.dispose](). Когда переменная выходит из области видимости, вызывается метод [Symbol.dispose]() объекта, чтобы гарантировать освобождение ресурсов.
Синтаксис
using name1 = value1; using name1 = value1, name2 = value2; using name1 = value1, name2 = value2, /* …, */ nameN = valueN;
-
nameN - Имя объявляемой переменной. Каждое должно быть допустимым идентификатором JavaScript и не шаблоном связывания деструктуризации.
-
valueN - Начальное значение переменной. Это может быть любое допустимое выражение, но его значение должно быть либо
null, либоundefined, либо объектом с методом[Symbol.dispose]().
Описание
Это объявление может использоваться:
- Внутри блока
- Внутри любого тела функции или блока статической инициализации класса
- На верхнем уровне модуля
- В инициализаторе цикла
for,for...of, илиfor await...of
В частности, его нельзя использовать:
- На верхнем уровне скрипта, поскольку области видимости скриптов являются постоянными.
- На верхнем уровне оператора
switch. - В инициализаторе цикла
for...in. Поскольку переменная цикла может быть только строкой или символом, это не имеет смысла.
using объявляет высвобождаемый ресурс, который привязан к времени жизни области видимости переменной (блока, функции, модуля и т. д.). Когда область видимости завершается, ресурс высвобождается синхронно. Переменной разрешено иметь значение null или undefined, поэтому ресурс может присутствовать опционально.
Когда переменная впервые объявлена и ее значение не является nullish, из объекта извлекается высвобождатель (disposer). Если свойство [Symbol.dispose] не содержит функцию, выбрасывается TypeError. Этот высвобождатель сохраняется в области видимости.
Когда переменная выходит из области видимости, высвобождатель вызывается. Если область видимости содержит несколько объявлений using или await using, все высвобождатели запускаются в обратном порядке объявления, независимо от типа объявления. Гарантируется, что все высвобождатели будут запущены (во многом как блок finally в try...catch...finally). Все ошибки, возникающие во время высвобождения, включая первоначальную ошибку, вызвавшую выход из области видимости (если применимо), агрегируются в одном SuppressedError, где каждое более раннее исключение является свойством suppressed, а более позднее исключение — свойством error. Этот SuppressedError выбрасывается после завершения высвобождения.
using привязывает управление ресурсами к лексическим областям видимости, что является одновременно удобным и иногда сбивающим с толку. Существует множество способов сохранить значение переменной, когда сама переменная находится вне области видимости, поэтому вы можете хранить ссылку на уже высвобожденный ресурс. См. ниже примеры, в которых поведение может быть не таким, как вы ожидаете. Если вы хотите управлять высвобождением ресурсов вручную, сохраняя при этом те же гарантии обработки ошибок, вы можете использовать DisposableStack вместо этого.
Примеры
В следующих примерах мы предполагаем наличие простого класса Resource, который имеет метод getValue и метод [Symbol.dispose]():
class Resource {
value = Math.random();
#isDisposed = false;
getValue() {
if (this.#isDisposed) {
throw new Error("Resource is disposed");
}
return this.value;
}
[Symbol.dispose]() {
this.#isDisposed = true;
console.log("Resource disposed");
}
}
using в блоке
Ресурс, объявленный с помощью using, высвобождается при выходе из блока.
{
using resource = new Resource();
console.log(resource.getValue());
// resource disposed here
}
using в функции
Вы можете использовать using в теле функции. В этом случае ресурс высвобождается, когда выполнение функции завершается, непосредственно перед возвратом функции.
function example() {
using resource = new Resource();
return resource.getValue();
}
Здесь resource[Symbol.dispose]() будет вызван после getValue(), до того как выполнится оператор return.
Ресурс может пережить объявление, в случае, если он захвачен замыканием:
function example() {
using resource = new Resource();
return () => resource.getValue();
}
В этом случае, если вы вызовете example()(), вы всегда будете выполнять getValue для уже высвобожденного ресурса, поскольку ресурс был высвобожден, когда example вернулась. Если вы хотите высвободить ресурс сразу после того, как колбэк был вызван один раз, рассмотрите следующий шаблон:
function example() {
const resource = new Resource();
return () => {
using resource2 = resource;
return resource2.getValue();
};
}
Здесь мы связываем ресурс, объявленный const, с ресурсом, объявленным using, чтобы ресурс высвобождался только после вызова колбэка; обратите внимание, что если он никогда не будет вызван, то ресурс никогда не будет очищен.
using в модуле
Вы можете использовать using на верхнем уровне модуля. В этом случае ресурс высвобождается, когда выполнение модуля завершается.
using resource = new Resource(); export const value = resource.getValue(); // resource disposed here
export using — это недопустимый синтаксис, но вы можете export переменную, объявленную где-либо еще, используя using:
using resource = new Resource();
export { resource };
Это все еще не рекомендуется, поскольку импортер всегда будет получать высвобожденный ресурс. Подобно проблеме с замыканием, это приводит к тому, что значение ресурса живет дольше, чем переменная.
using с for...of
Вы можете использовать using в инициализаторе цикла for...of. В этом случае ресурс высвобождается на каждой итерации цикла.
const resources = [new Resource(), new Resource(), new Resource()];
for (using resource of resources) {
console.log(resource.getValue());
// resource disposed here
}
Множественный using
Ниже приведены два эквивалентных способа объявления нескольких высвобождаемых ресурсов:
using resource1 = new Resource(), resource2 = new Resource(); // OR using resource1 = new Resource(); using resource2 = new Resource();
В обоих случаях, когда область видимости завершается, resource2 высвобождается перед resource1. Это связано с тем, что resource2 может иметь зависимость от resource1, поэтому он высвобождается первым, чтобы гарантировать, что resource1 все еще доступен, когда resource2 высвобождается.
Опциональный using
using позволяет переменной иметь значение null или undefined, поэтому ресурс может присутствовать опционально. Это означает, что, например, если вы проверяете доступность ресурса какого-либо типа:
function acquireResource() {
// Imagine some real-world relevant condition here,
// such as whether there's space to allocate for this resource
if (Math.random() < 0.5) {
return null;
}
return new Resource();
}
Вам не нужно делать это:
const maybeResource = acquireResource();
if (maybeResource) {
using resource = maybeResource;
console.log(resource.getValue());
} else {
console.log(undefined);
}
А вместо этого можно сделать так:
using resource = acquireResource(); console.log(resource?.getValue());
Объявление using без использования переменной
Вы можете добиться автоматического высвобождения ресурсов, используя using, даже не используя переменную. Это очень полезно для настройки контекста внутри блока, например, для создания блокировки:
{
using _ = new Lock();
// Perform concurrent operations here
// Lock disposed (released) here
}
Обратите внимание, что _ является обычным идентификатором, но существует соглашение использовать его как "выбрасываемую" переменную. Чтобы создать несколько неиспользуемых переменных, вам нужно использовать разные имена, например, используя имя переменной с префиксом _.
Инициализация и временные мертвые зоны
Переменные using подчиняются тому же ограничению временной мертвой зоны, что и переменные let и const. Это означает, что вы не можете получить доступ к переменной до инициализации — допустимое время жизни ресурса строго ограничено от его инициализации до конца его области видимости. Это позволяет управлять ресурсами в стиле RAII.
let useResource;
{
useResource = () => resource.getValue();
useResource(); // Error: Cannot access 'resource' before initialization
using resource = new Resource();
useResource(); // Valid
}
useResource(); // Error: Resource is disposed
Обработка ошибок
Объявление using наиболее полезно для управления высвобождением ресурсов при возникновении ошибок. Если вы будете невнимательны, некоторые ресурсы могут быть утечены, поскольку ошибка предотвращает выполнение последующего кода.
function handleResource(resource) {
if (resource.getValue() > 0.5) {
throw new Error("Resource value too high");
}
}
try {
using resource = new Resource();
handleResource(resource);
} catch (e) {
console.error(e);
}
Это позволит успешно перехватить ошибку, вызванную handleResource, и зарегистрировать ее, и независимо от того, выбрасывает ли handleResource ошибку или нет, ресурс высвобождается перед выходом из блока try.
Здесь, если вы не используете using, вы можете сделать что-то вроде:
try {
const resource = new Resource();
handleResource(resource);
resource[Symbol.dispose]();
} catch (e) {
console.error(e);
}
Но, если handleResource() выбрасывает ошибку, то управление никогда не достигнет resource[Symbol.dispose](), и ресурс будет утечен. Кроме того, если у вас есть два ресурса, то ошибки, возникшие при более раннем высвобождении, могут помешать выполнению более поздних высвобождений, что приведет к новым утечкам.
Рассмотрим более сложный случай, когда сам высвобождатель выбрасывает ошибку:
class CantDisposeMe {
#name;
constructor(name) {
this.#name = name;
}
[Symbol.dispose]() {
throw new Error(`Can't dispose ${this.#name}`);
}
}
let error;
try {
using resource1 = new CantDisposeMe("resource1");
using resource2 = new CantDisposeMe("resource2");
throw new Error("Error in main block");
} catch (e) {
error = e;
}
Вы можете просмотреть ошибку, выброшенную в консоли вашего браузера. Она имеет следующую структуру:
SuppressedError: An error was suppressed during disposal
suppressed: SuppressedError: An error was suppressed during disposal
suppressed: Error: Can't dispose resource1
error: Error: Error in main block
error: Error: Can't dispose resource2
Как видите, error содержит все ошибки, которые были выброшены во время высвобождения, в виде SuppressedError. Каждая дополнительная ошибка добавляется как свойство error, а исходная ошибка добавляется как свойство suppressed.
Спецификации
Совместимость с браузерами
| Десктопные | Мобильные | Серверные | |||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Chrome | Edge | Firefox | Opera | Safari | Chrome Android | Firefox for Android | Opera Android | Safari on iOS | Samsung Internet | WebView Android | WebView on iOS | Bun | Deno | Node.js | |
using |
134 |
134 |
141 |
119 |
preview |
134 |
141 |
88 |
Нет |
29.0 |
134 |
Нет |
1.0.23 |
1.37 |
24.0.0 |
См. также
© 2005–2025 MDN contributors.
Licensed under the Creative Commons Attribution-ShareAlike License v2.5 or later.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/using