The "using" keyword: A proposal to make JavaScript code safer and more concise
Table of contents
Have you ever unintentionally left a resource open while working on a JavaScript project? It may have been a web socket, a file handle, or a connection to a database. Whatever it was, you can probably relate to the frustration of attempting to debug your code but being unable to determine why it is malfunctioning. You then realise that the resource was never closed.
This is a typical issue that can result in memory leaks and other issues. The good news is that a new JavaScript keyword suggestion has been made that could be able to assist you avoid this issue.
The "using" keyword would create a temporary scope that contains the resource disposer function. This means that the disposer function would be called even if an exception is thrown.
Typescript 5.2 will introduce the "using" keyword, while this is still only a proposal for JavaScript. To understand how this will operate, let's first grasp Symbol.dispose.
A new global symbol in JavaScript is called Symbol.dispose. An object having a specified lifespan is referred to as a "resource" when it has a function given to Symbol.dispose, and may be utilized with the using keyword.
const resource = {
[Symbol.dispose]: () => {
console.log("Hooray!");
},
};
You can also use Symbol.asyncDispose and await using to handle resources that need to be disposed of asynchronously.
const getResource = () => ({
[Symbol.asyncDispose]: async () => {
await someAsyncFunc();
},
});
{
await using resource = getResource();
}
This will await the Symbol.asyncDispose function before continuing.
Use cases
File handles
Accessing the file system via file handlers could be a lot easier with using
.
Without using
:
import { open } from "node:fs/promises";
let filehandle;
try {
filehandle = await open("file.txt", "r");
} finally {
await filehandle?.close();
}
With using
:
import { open } from "node:fs/promises";
const getFileHandle = async (path: string) => {
const filehandle = await open(path, "r");
return {
filehandle,
[Symbol.asyncDispose]: async () => {
await filehandle.close();
},
};
};
{
await using file = getFileHandle("thefile.txt");
} // Automatically disposed!
Database connections
Managing database connections is a common use case for using
in C#.
Without using
:
const connection = await getDb();
try {
// Do stuff with connection
} finally {
await connection.close();
}
With using
:
const getConnection = async () => {
const connection = await getDb();
return {
connection,
[Symbol.asyncDispose]: async () => {
await connection.close();
},
};
};
{
await using db = getConnection();
// Do stuff with db.connection
} // Automatically closed!
The "using" keyword is currently just a suggestion, but it might make JavaScript code safer and shorter. So be sure to check it out if you're sick of forgetting to close resources!
JS proposal link
https://github.com/tc39/proposal-explicit-resource-management