• Web Developer
  • Posts
  • Explicit Resource Management in JS: The using Keyword

Explicit Resource Management in JS: The using Keyword

Simplify asynchronous and synchronous resource management

JavaScript is soon to introduce a new keyword: using. It is currently in the third stage (of four) of the TC39 proposal process, which means we will soon be able to use it in production.

This feature is inspired by similar concepts in C# and Rust, particularly Rust's ownership system, which automatically manages resource cleanup to prevent common errors like memory leaks and use-after-free bugs. It can automatically handle resources that implement the Symbol.dispose method when they are no longer needed, significantly simplifying resource management in applications.

Understanding Symbol.dispose

In JavaScript (and by extension, TypeScript), Symbol.dispose is a new global symbol that identifies objects designed to be managed resources. These are objects that have a finite lifecycle and need explicit cleanup after use to free up system resources. By assigning a function to Symbol.dispose, you define how the object should be cleaned up.

Here’s a simple example

const resource = {
  [Symbol.dispose]: () => {
    console.log("Resource has been cleaned up!");
  },
};

Using using for Synchronous Resource Management

The using keyword allows you to declare a resource that should be automatically disposed of once it goes out of scope. This is particularly useful for managing resources like file handles or network connections. Here's how you might use it:

{
  const getResource = () => ({
    [Symbol.dispose]: () => console.log('Resource is now disposed!')
  });

  using resource = getResource();
}
// Output: 'Resource is now disposed!'

This block ensures that as soon as the block is exited, the resource’s dispose method is called, thereby preventing resource leakage.

Asynchronous Resource Disposal with await using

For resources that require asynchronous cleanup, JavaScript supports await using. This is useful for operations that need to perform asynchronous tasks as part of their cleanup, like closing database connections or flushing buffers to a file.

Here’s an example using await using:

const getResourceAsync = () => ({
  [Symbol.asyncDispose]: async () => {
    await someAsyncCleanupFunction();
  }
});

{
  await using resource = getResourceAsync();
}

Practical Examples

Handling Database Connections

Database connections are a critical resource that needs careful management to avoid exhausting connection pools or holding onto unnecessary locks.

Without using:

const connection = await getDatabaseConnection();
try {
  // Query the database
} finally {
  await connection.close();
}

With using:

const getConnection = async () => {
  const connection = await getDatabaseConnection();
  return {
    connection,
    [Symbol.asyncDispose]: async () => await connection.close()
  };
};
​
{
  await using db = getConnection();
  // Use db.connection for queries
}
// Connection is automatically closed here

Managing File Handles

Handling files often requires meticulous resource management to avoid leaving open file handles that can lock files or consume memory. Here’s how you might handle a file with and without using:

Without using:

import { open } from "node:fs/promises";
​
let fileHandle;
try {
  fileHandle = await open("example.txt", "r");
  // Read or write to the file
} finally {
  if (fileHandle) {
    await fileHandle.close();
  }
}

With using:

import { open } from "node:fs/promises";
​
const getFileHandle = async (path) => {
  const fileHandle = await open(path, "r");
  return {
    fileHandle,
    [Symbol.asyncDispose]: async () => await fileHandle.close()
  };
};
​
{
  await using file = getFileHandle("example.txt");
  // Operate on file.fileHandle
}
// File is automatically closed after this block

Conclusion

This feature not only reduces boilerplate code but also helps in preventing common programming errors related to resource management, bringing JavaScript closer to the safety and convenience seen in languages like Rust and C#.

If you find my content helpful, please consider subscribing. I send a weekly newsletter every Sunday with the latest web development updates. Thanks for your support!

Join the conversation

or to participate.