TypeScript using کی ورڈ اور Explicit Resource Management

پروڈکشن میں میموری لیکس (memory leaks) اکثر ایک ہی غلطی کی وجہ سے ہوتے ہیں: ڈویلپرز ریسورسز حاصل تو کر لیتے ہیں لیکن انہیں ریلیز (release) کرنے میں ناکام رہتے ہیں۔

ڈیٹا بیس کنکشنز غلطیوں کے بعد بھی کھلے رہ جاتے ہیں۔ فائل ہینڈلز سسٹم کے وسائل استعمال کرتے رہتے ہیں۔ WebSocket کلائنٹس مردہ سرورز سے جڑے رہتے ہیں۔ ایسا اس وقت ہوتا ہے جب آپ finally بلاکس میں دستی صفائی (manual cleanup) پر بھروسہ کرتے ہیں۔

TypeScript کا using کی ورڈ اس مسئلے کو حل کرتا ہے۔ یہ ECMAScript Explicit Resource Management تجویز کا حصہ ہے۔ یہ disposable پیٹرن کے ذریعے صفائی کی ضمانت دیتا ہے۔ جب کوئی ریسورس اپنے اسکوپ (scope) سے باہر نکلتا ہے، تو TypeScript خود بخود اس کا disposal میتھڈ چلا دیتا ہے۔

اب آپ کو دستی finally بلاکس کی ضرورت نہیں ہے۔ اب آپ صفائی کرنا نہیں بھولیں گے۔ اب آپ کے کنکشنز لیک نہیں ہوں گے۔

یہ کیسے کام کرتا ہے:

  • using کی ورڈ اس بات کو یقینی بناتا ہے کہ جب ریسورسز اسکوپ سے باہر نکلیں تو ان کا disposal ہو جائے۔
  • Disposable ریسورسز سنکرونس (sync) کاموں کے لیے Symbol.dispose یا اسینکرونس (async) کاموں کے لیے Symbol.asyncDispose کو امپلیمنٹ کرتے ہیں۔
  • TypeScript using ڈیکلیریشنز کو ایک خودکار disposal stack کے ساتھ try-finally بلاکس میں تبدیل کر دیتا ہے۔
  • یہ پیٹرن جلد واپسی (early returns)، تھرو ہونے والے استثنائی حالات (exceptions)، یا بھولے ہوئے کوڈ کی وجہ سے ہونے والے لیکس کو روکتا ہے۔

کسی بھی ایسے ریسورس کے لیے using کا استعمال کریں جس کی ایک مقررہ مدت ہو، جیسے کہ ڈیٹا بیس کنکشنز، فائل ہینڈلز، لاکس، یا ٹائمرز۔

یہ میکانزم ایک disposal پروٹوکول استعمال کرتا ہے۔ آبجیکٹس ایک ایسا میتھڈ امپلیمنٹ کرتے ہیں جس کی کی (key) Symbol.dispose ہوتی ہے۔ جب اسکوپ نارمل تکمیل، ریٹرن، یا کسی استثنا (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 ایک تیار کردہ (generated) finally بلاک میں چلتا ہے۔ یہ تب بھی چلتا ہے اگر فنکشن کوئی ایرر تھرو کرے یا جلد واپس (return) آ جائے۔

TypeScript ایک disposal stack برقرار رکھتا ہے۔ یہ ریسورسز کو ان کے حاصل کرنے کے الٹ ترتیب (reverse order) میں ڈسپوز کرتا ہے۔ یہ زیادہ تر صفائی کے لاجک کے لیے قدرتی انحصار کی ترتیب (dependency order) کے مطابق ہوتا ہے۔

اسینکرونس صفائی کے لیے، await using استعمال کریں۔ اس کے لیے ضروری ہے کہ ریسورس Symbol.asyncDispose کو امپلیمنٹ کرے۔ TypeScript آگے بڑھنے سے پہلے واپس آنے والے Promise کا انتظار (await) کرے گا۔

کامیابی کے لیے تین اصول:

  • اپنے disposal میتھڈز کے اندر استثنا (exceptions) تھرو نہ کریں۔ اس کے بجائے ایررز کو اندرونی طور پر پکڑیں (catch کریں) اور لاگ کریں۔
  • سنکرونس 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