TypeScript using കീവേഡും എക്സ്പ്ലിസിറ്റ് റിസോഴ്‌സ് മാനേജ്‌മെന്റും (Explicit Resource Management)

പ്രൊഡക്ഷനിലെ മെമ്മറി ലീക്കുകൾ (Memory leaks) പലപ്പോഴും ഒരു തെറ്റിൽ നിന്നാണ് ഉണ്ടാകുന്നത്: ഡെവലപ്പർമാർ റിസോഴ്‌സുകൾ ഉപയോഗിക്കുന്നുണ്ടെങ്കിലും അവ കൃത്യസമയത്ത് റിലീസ് ചെയ്യാൻ പരാജയപ്പെടുന്നു.

എററുകൾക്ക് ശേഷവും ഡാറ്റാബേസ് കണക്ഷനുകൾ തുറന്നുതന്നെ ഇരിക്കുന്നു. ഫയൽ ഹാൻഡിലുകൾ (File handles) സിസ്റ്റം റിസോഴ്‌സുകൾ ഉപയോഗിച്ചുകൊണ്ടിരിക്കുന്നു. വെബ്‌സോക്കറ്റ് (WebSocket) ക്ലയന്റുകൾ പ്രവർത്തിക്കാത്ത സെർവറുകളുമായി ബന്ധിതമായി തുടരുന്നു. finally ബ്ലോക്കുകളിലെ മാനുവൽ ക്ലീനപ്പിനെ (manual cleanup) മാത്രം ആശ്രയിക്കുമ്പോഴാണ് ഇത് സംഭവിക്കുന്നത്.

TypeScript-ലെ using കീവേഡ് ഈ പ്രശ്നം പരിഹരിക്കുന്നു. ഇത് ECMAScript-ന്റെ Explicit Resource Management പ്രൊപ്പോസലിന്റെ ഭാഗമാണ്. 'Disposable pattern' വഴി ക്ലീനപ്പ് ഉറപ്പാക്കാൻ ഇത് സഹായിക്കുന്നു. ഒരു റിസോഴ്‌സ് അതിന്റെ സ്കോപ്പിൽ (scope) നിന്ന് പുറത്തുവരുമ്പോൾ, TypeScript അതിന്റെ ഡിസ്പോസൽ മെത്തേഡ് (disposal method) സ്വയമേവ പ്രവർത്തിപ്പിക്കുന്നു.

ഇനി നിങ്ങൾക്ക് മാനുവൽ finally ബ്ലോക്കുകൾ ആവശ്യമില്ല. ക്ലീനപ്പ് ചെയ്യാൻ നിങ്ങൾ മറന്നുപോകില്ല. കണക്ഷനുകൾ ലീക്ക് ചെയ്യപ്പെടുകയുമില്ല.

ഇത് എങ്ങനെ പ്രവർത്തിക്കുന്നു:

  • റിസോഴ്‌സുകൾ ഒരു സ്കോപ്പിൽ നിന്ന് പുറത്തുവരുമ്പോൾ using കീവേഡ് അവയുടെ ഡിസ്പോസൽ ഉറപ്പാക്കുന്നു.
  • ഡിസ്പോസിബിൾ റിസോഴ്‌സുകൾ സിങ്ക് (sync) ടാസ്ക്കുകൾക്കായി Symbol.dispose-ഉം അസിങ്ക് (async) ടാസ്ക്കുകൾക്കായി Symbol.asyncDispose-ഉം ഉപയോഗിക്കുന്നു.
  • TypeScript using ഡിക്ലറേഷനുകളെ ഒരു ഓട്ടോമാറ്റിക് ഡിസ്പോസൽ സ്റ്റാക്ക് ഉള്ള try-finally ബ്ലോക്കുകളാക്കി മാറ്റുന്നു.
  • ഈ പാറ്റേൺ നേരത്തെയുള്ള റിട്ടേണുകൾ (early returns), എക്സെപ്ഷനുകൾ (exceptions), അല്ലെങ്കിൽ മറന്നുപോയ കോഡുകൾ എന്നിവ മൂലമുണ്ടാകുന്ന ലീക്കുകൾ തടയുന്നു.

ഡാറ്റാബേസ് കണക്ഷനുകൾ, ഫയൽ ഹാൻഡിലുകൾ, ലോക്കുകൾ (locks), അല്ലെങ്കിൽ ടൈമറുകൾ എന്നിങ്ങനെ നിശ്ചിത കാലയളവുള്ള ഏത് റിസോഴ്‌സിനും using ഉപയോഗിക്കാം.

ഈ സംവിധാനം ഒരു ഡിസ്പോസൽ പ്രോട്ടോക്കോൾ (disposal protocol) ആണ് ഉപയോഗിക്കുന്നത്. ഒബ്‌ജക്റ്റുകൾ Symbol.dispose ഉപയോഗിച്ച് ഒരു മെത്തേഡ് നടപ്പിലാക്കുന്നു. സ്കോപ്പ് സാധാരണ രീതിയിലോ, ഒരു return-ലൂടെയോ, അല്ലെങ്കിൽ ഒരു എക്സെപ്ഷൻ വഴിയോ അവസാനിക്കുമ്പോൾ 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);
}

ഡിസ്പോസൽ ഒരു ജനറേറ്റഡ് finally ബ്ലോക്കിൽ പ്രവർത്തിക്കുന്നു. ഫംഗ്ഷൻ ഒരു എറർ എറിഞ്ഞാലോ അല്ലെങ്കിൽ നേരത്തെ റിട്ടേൺ ചെയ്താലോ പോലും ഇത് പ്രവർത്തിക്കും.

TypeScript ഒരു ഡിസ്പോസൽ സ്റ്റാക്ക് (disposal stack) നിലനിർത്തുന്നു. നിങ്ങൾ റിസോഴ്‌സുകൾ നേടിയ ക്രമത്തിന്റെ വിപരീത ദിശയിലാണ് അവ ഡിസ്പോസ് ചെയ്യുന്നത്. മിക്ക ക്ലീനപ്പ് ലോജിക്കുകളുടെയും സ്വാഭാവികമായ ഡിപെൻഡൻസി ഓർഡറിന് (dependency order) ഇത് അനുയോജ്യമാണ്.

അസിൻക്രണസ് ക്ലീനപ്പിനായി (asynchronous cleanup) await using ഉപയോഗിക്കുക. ഇതിനായി റിസോഴ്‌സ് Symbol.asyncDispose നടപ്പിലാക്കിയിരിക്കണം. തുടർന്ന് പ്രവർത്തിക്കുന്നതിന് മുമ്പ് TypeScript റിട്ടേൺ ചെയ്ത പ്രോമിസിനായി (Promise) കാത്തിരിക്കും.

വിജയകരമായി ഉപയോഗിക്കാൻ മൂന്ന് നിയമങ്ങൾ:

  • നിങ്ങളുടെ ഡിസ്പോസൽ മെത്തേഡുകൾക്കുള്ളിൽ എക്സെപ്ഷനുകൾ എറിയരുത്. പകരം എററുകൾ ക്യാച്ച് ചെയ്ത് ലോഗ് ചെയ്യുക.
  • സിൻക്രണസ് ആയ 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