TypeScript using কিওয়ার্ড এবং Explicit Resource Management
প্রোডাকশনে মেমরি লিক (Memory leaks) প্রায়শই একটি ভুলের কারণে ঘটে: ডেভেলপাররা রিসোর্স গ্রহণ করেন কিন্তু সেগুলো রিলিজ করতে ব্যর্থ হন।
এরর বা ত্রুটির পরেও ডাটাবেস কানেকশনগুলো খোলা থেকে যায়। ফাইল হ্যান্ডেলগুলো সিস্টেম রিসোর্স দখল করে রাখে। WebSocket ক্লায়েন্টগুলো মৃত সার্ভারের সাথে কানেক্টেড থেকে যায়। এটি তখনই ঘটে যখন আপনি finally ব্লকে ম্যানুয়াল ক্লিনআপের ওপর নির্ভর করেন।
TypeScript-এর using কিওয়ার্ড এই সমস্যার সমাধান করে। এটি ECMAScript Explicit Resource Management প্রপোজালের একটি অংশ। এটি 'disposable pattern'-এর মাধ্যমে ক্লিনআপ নিশ্চিত করে। যখন কোনো রিসোর্স তার স্কোপ (scope) থেকে বেরিয়ে যায়, TypeScript স্বয়ংক্রিয়ভাবে তার disposal মেথডটি রান করে।
আপনার আর ম্যানুয়াল finally ব্লকের প্রয়োজন নেই। আপনি আর ক্লিনআপ করতে ভুলে যাবেন না। আপনার আর কানেকশন লিক হবে না।
এটি যেভাবে কাজ করে:
usingকিওয়ার্ড রিসোর্স স্কোপ থেকে বেরিয়ে গেলে তার disposal নিশ্চিত করে।- Disposable রিসোর্সগুলো সিনক্রোনাস (sync) কাজের জন্য
Symbol.disposeঅথবা অ্যাসিনক্রোনাস (async) কাজের জন্যSymbol.asyncDisposeইমপ্লিমেন্ট করে। - TypeScript
usingডিক্লারেশনগুলোকে একটি স্বয়ংক্রিয় disposal stack সহtry-finallyব্লকে রূপান্তরিত করে। - এই প্যাটার্নটি early returns, thrown exceptions বা ভুলে যাওয়া কোডের কারণে হওয়া লিক প্রতিরোধ করে।
নির্দিষ্ট লাইফটাইম আছে এমন যেকোনো রিসোর্সের জন্য using ব্যবহার করুন, যেমন ডাটাবেস কানেকশন, ফাইল হ্যান্ডেল, লক (locks) বা টাইমার।
এই মেকানিজমটি একটি disposal protocol ব্যবহার করে। অবজেক্টগুলো Symbol.dispose কী (key) যুক্ত একটি মেথড ইমপ্লিমেন্ট করে। যখন স্কোপটি স্বাভাবিকভাবে সম্পন্ন হয়, return হয় অথবা কোনো এরর (exception) ঘটে, তখন TypeScript সেই মেথডটি কল করে।
একটি ফাইল হ্যান্ডেলের উদাহরণ:
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);
}
Disposal-টি একটি জেনারেটেড finally ব্লকে রান করে। ফাংশনটি এরর থ্রো করলে বা দ্রুত রিটার্ন করলেও এটি রান করে।
TypeScript একটি disposal stack বজায় রাখে। আপনি যেভাবে রিসোর্সগুলো গ্রহণ করেছেন, তার ঠিক উল্টো ক্রমে (reverse order) এটি রিসোর্সগুলো ডিসপোজ করে। এটি বেশিরভাগ ক্লিনআপ লজিকের স্বাভাবিক ডিপেন্ডেন্সি অর্ডারের সাথে মিলে যায়।
অ্যাসিনক্রোনাস ক্লিনআপের জন্য await using ব্যবহার করুন। এর জন্য রিসোর্সটিকে অবশ্যই Symbol.asyncDispose ইমপ্লিমেন্ট করতে হবে। TypeScript পরবর্তী ধাপে যাওয়ার আগে রিটার্ন করা Promise-টির জন্য await করবে।
সফল হওয়ার জন্য তিনটি নিয়ম:
- আপনার disposal মেথডগুলোর ভেতরে কোনো exception থ্রো করবেন না। পরিবর্তে এররগুলো ইন্টারনালি ক্যাচ (catch) এবং লগ (log) করুন।
- একটি সিনক্রোনাস
Symbol.disposeমেথডের ভেতরে অ্যাসিনক্রোনাস অপারেশন ব্যবহার করবেন না। পরিবর্তেSymbol.asyncDisposeব্যবহার করুন। - মনে রাখবেন যে
usingডিক্লারেশনগুলো block-scoped। একটিifব্লকের ভেতরের রিসোর্স সেই ব্লকটি শেষ হলেই ডিসপোজ হয়ে যায়, ফাংশন শেষ হওয়ার অপেক্ষায় থাকে না।
এই প্যাটার্নটি খুব সামান্য রানটাইম কস্টের (runtime cost) বিনিময়ে নিরাপত্তা প্রদান করে।
Source: https://dev.to/jsmanifest/typescript-using-keyword-and-explicit-resource-management-done-right-22pg
