La parola chiave using in TypeScript e la gestione esplicita delle risorse
I memory leak in produzione spesso derivano da un unico errore: gli sviluppatori acquisiscono risorse ma non riescono a rilasciarle.
Le connessioni al database rimangono aperte dopo un errore. Gli handle dei file consumano risorse di sistema. I client WebSocket rimangono connessi a server inattivi. Ciò accade quando ci si affida alla pulizia manuale all'interno dei blocchi finally.
La parola chiave using di TypeScript risolve questo problema. Fa parte della proposta ECMAScript "Explicit Resource Management". Garantisce la pulizia attraverso il pattern disposable. Quando una risorsa esce dal suo scope, TypeScript esegue automaticamente il suo metodo di smaltimento.
Non avrai più bisogno di blocchi finally manuali. Non dimenticherai più la pulizia. Non avrai più perdite di connessioni.
Come funziona:
- La parola chiave
usinggarantisce lo smaltimento quando le risorse escono da uno scope. - Le risorse disposable implementano
Symbol.disposeper i task sincroni oSymbol.asyncDisposeper i task asincroni. - TypeScript trasforma le dichiarazioni
usingin blocchitry-finallycon uno stack di smaltimento automatico. - Questo pattern previene i leak causati da ritorni anticipati, eccezioni lanciate o codice dimenticato.
Usa using per qualsiasi risorsa con un ciclo di vita definito, come connessioni al database, handle di file, lock o timer.
Il meccanismo utilizza un protocollo di smaltimento. Gli oggetti implementano un metodo identificato da Symbol.dispose. Quando lo scope termina tramite completamento normale, un return o un'eccezione, TypeScript chiama quel metodo.
Esempio di un handle di file:
class FileHandle {
private handle: number;
constructor(path: string) {
this.handle = openFileSync(path);
}
[Symbol.dispose]() {
if (this.handle !== -1) {
closeFileSync(this.handle);
this.handle = -1;
}
}
read(buffer: Buffer): number {
return readSync(this.handle, buffer);
}
}
function processFile(path: string) {
using file = new FileHandle(path);
const buffer = Buffer.alloc(1024);
file.read(buffer);
}
Lo smaltimento viene eseguito in un blocco finally generato. Viene eseguito anche se la funzione lancia un errore o ritorna anticipatamente.
TypeScript mantiene uno stack di smaltimento. Smaltisce le risorse in ordine inverso rispetto a come sono state acquisite. Questo corrisponde all'ordine naturale di dipendenza per la maggior parte della logica di pulizia.
Per la pulizia asincrona, usa await using. Ciò richiede che la risorsa implementi Symbol.asyncDispose. TypeScript attenderà la Promise restituita prima di procedere.
Tre regole per il successo:
- Non lanciare eccezioni all'interno dei metodi di smaltimento. Cattura e registra gli errori internamente.
- Non utilizzare operazioni asincrone all'interno di un metodo
Symbol.disposesincrono. Usa inveceSymbol.asyncDispose. - Ricorda che le dichiarazioni
usinghanno uno scope di blocco. Una risorsa all'interno di un bloccoifviene smaltita quando il blocco termina, non quando termina la funzione.
Questo pattern offre sicurezza con un costo di runtime trascurabile.
Fonte: https://dev.to/jsmanifest/typescript-using-keyword-and-explicit-resource-management-done-right-22pg
