അഡ്വാൻസ്ഡ് ജാവാസ്ക്രിപ്റ്റ് റിസോഴ്സ് മാനേജ്മെന്റിനെക്കുറിച്ചുള്ള ആഴത്തിലുള്ള പഠനം. 'using' ഡിക്ലറേഷൻ റിസോഴ്സ് പൂളിംഗുമായി സംയോജിപ്പിച്ച് വൃത്തിയുള്ളതും സുരക്ഷിതവും ഉയർന്ന പ്രകടനശേഷിയുള്ളതുമായ ആപ്ലിക്കേഷനുകൾ നിർമ്മിക്കാൻ പഠിക്കുക.
റിസോഴ്സ് മാനേജ്മെന്റിൽ വൈദഗ്ദ്ധ്യം നേടാം: ജാവാസ്ക്രിപ്റ്റിലെ 'using' സ്റ്റേറ്റ്മെന്റും റിസോഴ്സ് പൂളിംഗ് തന്ത്രവും
ഉയർന്ന പ്രകടനശേഷിയുള്ള സെർവർ-സൈഡ് ജാവാസ്ക്രിപ്റ്റിന്റെ ലോകത്ത്, പ്രത്യേകിച്ച് Node.js, Deno പോലുള്ള പ്ലാറ്റ്ഫോമുകളിൽ, കാര്യക്ഷമമായ റിസോഴ്സ് മാനേജ്മെന്റ് ഒരു നല്ല ശീലം മാത്രമല്ല; വികസിപ്പിക്കാവുന്നതും, പ്രതിരോധശേഷിയുള്ളതും, ചെലവ് കുറഞ്ഞതുമായ ആപ്ലിക്കേഷനുകൾ നിർമ്മിക്കുന്നതിനുള്ള ഒരു നിർണായക ഘടകം കൂടിയാണ് അത്. ഡാറ്റാബേസ് കണക്ഷനുകൾ, ഫയൽ ഹാൻഡിലുകൾ, നെറ്റ്വർക്ക് സോക്കറ്റുകൾ, അല്ലെങ്കിൽ വർക്കർ ത്രെഡുകൾ പോലുള്ള പരിമിതവും, നിർമ്മിക്കാൻ ചെലവേറിയതുമായ റിസോഴ്സുകൾ കൈകാര്യം ചെയ്യുന്നതിൽ ഡെവലപ്പർമാർ പലപ്പോഴും ബുദ്ധിമുട്ടാറുണ്ട്. ഈ റിസോഴ്സുകൾ തെറ്റായി കൈകാര്യം ചെയ്യുന്നത് മെമ്മറി ലീക്കുകൾ, കണക്ഷൻ തീർന്നുപോകൽ, സിസ്റ്റം അസ്ഥിരത, പ്രകടനത്തകർച്ച തുടങ്ങിയ പ്രശ്നങ്ങളുടെ ഒരു പരമ്പരയിലേക്ക് നയിച്ചേക്കാം.
പരമ്പരാഗതമായി, റിസോഴ്സുകൾ വൃത്തിയാക്കുന്നുവെന്ന് ഉറപ്പാക്കാൻ ഡെവലപ്പർമാർ try...catch...finally
ബ്ലോക്കിനെയാണ് ആശ്രയിച്ചിരുന്നത്. ഇത് ഫലപ്രദമാണെങ്കിലും, ഈ രീതി ദൈർഘ്യമേറിയതും പിശകുകൾക്ക് സാധ്യതയുള്ളതുമാണ്. മറുവശത്ത്, പ്രകടനമികവിനായി, ഈ ആസ്തികൾ തുടർച്ചയായി സൃഷ്ടിക്കുന്നതിനും നശിപ്പിക്കുന്നതിനുമുള്ള ഓവർഹെഡ് ഒഴിവാക്കാൻ നമ്മൾ റിസോഴ്സ് പൂളിംഗ് ഉപയോഗിക്കുന്നു. എന്നാൽ ഉറപ്പായ ക്ലീനപ്പിന്റെ സുരക്ഷയും റിസോഴ്സ് പുനരുപയോഗത്തിന്റെ കാര്യക്ഷമതയും എങ്ങനെ മനോഹരമായി സംയോജിപ്പിക്കാം? ഉത്തരം രണ്ട് ആശയങ്ങളുടെ ശക്തമായ സമന്വയത്തിലാണ്: മറ്റ് ഭാഷകളിൽ കാണുന്ന using
സ്റ്റേറ്റ്മെന്റിന് സമാനമായ ഒരു പാറ്റേണും, തെളിയിക്കപ്പെട്ട റിസോഴ്സ് പൂളിംഗ് തന്ത്രവും.
ഈ സമഗ്രമായ ഗൈഡ്, ആധുനിക ജാവാസ്ക്രിപ്റ്റിൽ എങ്ങനെ കരുത്തുറ്റ ഒരു റിസോഴ്സ് മാനേജ്മെന്റ് തന്ത്രം രൂപപ്പെടുത്താമെന്ന് വിശദീകരിക്കും. using
, await using
എന്നീ കീവേഡുകൾ അവതരിപ്പിക്കുന്ന, എക്സ്പ്ലിസിറ്റ് റിസോഴ്സ് മാനേജ്മെന്റിനായുള്ള വരാനിരിക്കുന്ന TC39 പ്രൊപ്പോസലിനെക്കുറിച്ച് നമ്മൾ ആഴത്തിൽ പഠിക്കുകയും, ശക്തവും പരിപാലിക്കാൻ എളുപ്പമുള്ളതുമായ ആപ്ലിക്കേഷനുകൾ നിർമ്മിക്കുന്നതിന് ഈ വൃത്തിയുള്ളതും ഡിക്ലറേറ്റീവുമായ സിന്റാക്സ് ഒരു കസ്റ്റം റിസോഴ്സ് പൂളുമായി എങ്ങനെ സംയോജിപ്പിക്കാമെന്ന് പ്രായോഗികമായി കാണിക്കുകയും ചെയ്യും.
പ്രധാന പ്രശ്നം മനസ്സിലാക്കൽ: ജാവാസ്ക്രിപ്റ്റിലെ റിസോഴ്സ് മാനേജ്മെന്റ്
ഒരു പരിഹാരം നിർമ്മിക്കുന്നതിന് മുമ്പ്, പ്രശ്നത്തിന്റെ സൂക്ഷ്മതകൾ മനസ്സിലാക്കേണ്ടത് അത്യാവശ്യമാണ്. ഈ സന്ദർഭത്തിൽ 'റിസോഴ്സുകൾ' എന്ന് കൃത്യമായി എന്താണ് അർത്ഥമാക്കുന്നത്, അവയെ കൈകാര്യം ചെയ്യുന്നത് സാധാരണ മെമ്മറി കൈകാര്യം ചെയ്യുന്നതിൽ നിന്ന് എങ്ങനെ വ്യത്യസ്തമാകുന്നു?
എന്താണ് 'റിസോഴ്സുകൾ'?
ഈ ചർച്ചയിൽ, 'റിസോഴ്സ്' എന്നത് ഒരു ബാഹ്യ സിസ്റ്റവുമായി ബന്ധം സ്ഥാപിച്ചിട്ടുള്ളതോ അല്ലെങ്കിൽ വ്യക്തമായ 'close', 'disconnect' പ്രവർത്തനം ആവശ്യമുള്ളതോ ആയ ഏതൊരു ഒബ്ജക്റ്റിനെയും സൂചിപ്പിക്കുന്നു. ഇവ പലപ്പോഴും എണ്ണത്തിൽ പരിമിതവും സ്ഥാപിക്കാൻ കമ്പ്യൂട്ടേഷണലി ചെലവേറിയതുമാണ്. സാധാരണ ഉദാഹരണങ്ങൾ താഴെ പറയുന്നവയാണ്:
- ഡാറ്റാബേസ് കണക്ഷനുകൾ: ഒരു ഡാറ്റാബേസുമായി കണക്ഷൻ സ്ഥാപിക്കുന്നതിൽ നെറ്റ്വർക്ക് ഹാൻഡ്ഷേക്ക്, ഓതന്റിക്കേഷൻ, സെഷൻ സെറ്റപ്പ് എന്നിവ ഉൾപ്പെടുന്നു, ഇവയെല്ലാം സമയവും സിപിയു സൈക്കിളുകളും ഉപയോഗിക്കുന്നു.
- ഫയൽ ഹാൻഡിലുകൾ: ഒരു പ്രോസസ്സിന് ഒരേ സമയം തുറക്കാൻ കഴിയുന്ന ഫയലുകളുടെ എണ്ണം ഓപ്പറേറ്റിംഗ് സിസ്റ്റങ്ങൾ പരിമിതപ്പെടുത്തുന്നു. ലീക്ക് ആയ ഫയൽ ഹാൻഡിലുകൾ ഒരു ആപ്ലിക്കേഷന് പുതിയ ഫയലുകൾ തുറക്കുന്നതിൽ നിന്ന് തടയാം.
- നെറ്റ്വർക്ക് സോക്കറ്റുകൾ: ബാഹ്യ എപിഐകൾ, മെസ്സേജ് ക്യൂകൾ, അല്ലെങ്കിൽ മറ്റ് മൈക്രോസർവീസുകളുമായുള്ള കണക്ഷനുകൾ.
- വർക്കർ ത്രെഡുകൾ അല്ലെങ്കിൽ ചൈൽഡ് പ്രോസസ്സുകൾ: പ്രോസസ്സ് ക്രിയേഷൻ ഓവർഹെഡ് ഒഴിവാക്കാൻ ഒരു പൂളിൽ കൈകാര്യം ചെയ്യേണ്ട കനത്ത കമ്പ്യൂട്ടേഷണൽ റിസോഴ്സുകൾ.
എന്തുകൊണ്ട് ഗാർബേജ് കളക്ടർ മാത്രം മതിയാവില്ല
സിസ്റ്റംസ് പ്രോഗ്രാമിംഗിൽ പുതിയവരായ ഡെവലപ്പർമാർക്കിടയിലുള്ള ഒരു സാധാരണ തെറ്റിദ്ധാരണയാണ് ജാവാസ്ക്രിപ്റ്റിന്റെ ഗാർബേജ് കളക്ടർ (GC) എല്ലാം കൈകാര്യം ചെയ്യും എന്നത്. ഇനി റീച്ച് ചെയ്യാൻ കഴിയാത്ത ഒബ്ജക്റ്റുകൾ കൈവശം വെച്ചിരിക്കുന്ന മെമ്മറി വീണ്ടെടുക്കുന്നതിൽ GC വളരെ മികച്ചതാണ്. എന്നിരുന്നാലും, അത് ബാഹ്യ റിസോഴ്സുകളെ ഒരു നിശ്ചിത രീതിയിൽ (deterministically) കൈകാര്യം ചെയ്യുന്നില്ല.
ഒരു ഡാറ്റാബേസ് കണക്ഷനെ പ്രതിനിധീകരിക്കുന്ന ഒബ്ജക്റ്റ് ഇനി റഫർ ചെയ്യപ്പെടാതിരിക്കുമ്പോൾ, GC ഒടുവിൽ അതിന്റെ മെമ്മറി സ്വതന്ത്രമാക്കും. എന്നാൽ ഇത് എപ്പോൾ സംഭവിക്കുമെന്ന് യാതൊരു ഉറപ്പുമില്ല, കൂടാതെ ഓപ്പറേറ്റിംഗ് സിസ്റ്റത്തിലേക്ക് നെറ്റ്വർക്ക് സോക്കറ്റ് തിരികെ നൽകുന്നതിനോ ഡാറ്റാബേസ് സെർവറിലേക്ക് കണക്ഷൻ സ്ലോട്ട് തിരികെ നൽകുന്നതിനോ ഒരു .close()
മെത്തേഡ് വിളിക്കേണ്ടതുണ്ടെന്ന് അതിന് അറിയില്ല. റിസോഴ്സ് ക്ലീനപ്പിനായി GC-യെ ആശ്രയിക്കുന്നത് അനിശ്ചിതമായ പെരുമാറ്റത്തിലേക്കും റിസോഴ്സ് ലീക്കുകളിലേക്കും നയിക്കുന്നു, അവിടെ നിങ്ങളുടെ ആപ്ലിക്കേഷൻ വിലയേറിയ കണക്ഷനുകൾ ആവശ്യത്തിലധികം നേരം കൈവശം വയ്ക്കുന്നു.
'using' സ്റ്റേറ്റ്മെന്റ് അനുകരിക്കൽ: ഡിറ്റർമിനിസ്റ്റിക് ക്ലീനപ്പിലേക്കുള്ള ഒരു പാത
സി# (using
ഉപയോഗിച്ച്), പൈത്തൺ (with
ഉപയോഗിച്ച്) പോലുള്ള ഭാഷകൾ ഒരു റിസോഴ്സിന്റെ ക്ലീനപ്പ് ലോജിക് അത് സ്കോപ്പിൽ നിന്ന് പുറത്തുപോകുമ്പോൾ തന്നെ എക്സിക്യൂട്ട് ചെയ്യുമെന്ന് ഉറപ്പ് നൽകുന്നതിന് മികച്ച സിന്റാക്സ് നൽകുന്നു. ഈ ആശയത്തെ ഡിറ്റർമിനിസ്റ്റിക് റിസോഴ്സ് മാനേജ്മെന്റ് എന്ന് വിളിക്കുന്നു. ജാവാസ്ക്രിപ്റ്റിന് ഒരു നേറ്റീവ് പരിഹാരം ലഭിക്കുന്നതിന്റെ വക്കിലാണ്, എന്നാൽ ആദ്യം നമുക്ക് പരമ്പരാഗത രീതി നോക്കാം.
ക്ലാസിക് സമീപനം: try...finally
ബ്ലോക്ക്
ജാവാസ്ക്രിപ്റ്റിലെ റിസോഴ്സ് മാനേജ്മെന്റിന്റെ പ്രധാന ആശ്രയം എപ്പോഴും try...finally
ബ്ലോക്ക് ആയിരുന്നു. try
ബ്ലോക്കിലെ കോഡ് വിജയകരമായി പൂർത്തിയാക്കിയാലും, ഒരു പിശക് സംഭവിച്ചാലും, അല്ലെങ്കിൽ ഒരു വാല്യൂ റിട്ടേൺ ചെയ്താലും finally
ബ്ലോക്കിലെ കോഡ് എക്സിക്യൂട്ട് ചെയ്യുമെന്ന് ഉറപ്പാണ്.
ഒരു ഡാറ്റാബേസ് കണക്ഷൻ കൈകാര്യം ചെയ്യുന്നതിനുള്ള ഒരു സാധാരണ ഉദാഹരണം ഇതാ:
async function getUserById(id) {
let connection;
try {
connection = await getDatabaseConnection(); // Acquire resource
const result = await connection.query('SELECT * FROM users WHERE id = ?', [id]);
return result[0];
} catch (error) {
console.error("An error occurred during the query:", error);
throw error; // Re-throw the error
} finally {
if (connection) {
await connection.close(); // ALWAYS release resource
}
}
}
ഈ പാറ്റേൺ പ്രവർത്തിക്കുമെങ്കിലും, ഇതിന് ചില ദോഷങ്ങളുണ്ട്:
- ദൈർഘ്യം: റിസോഴ്സ് നേടുന്നതിനും റിലീസ് ചെയ്യുന്നതിനുമുള്ള ബോയിലർപ്ലേറ്റ് കോഡ് പലപ്പോഴും യഥാർത്ഥ ബിസിനസ് ലോജിക്കിനെക്കാൾ വലുതായിരിക്കും.
- പിശകുകൾക്ക് സാധ്യത:
if (connection)
ചെക്ക് മറന്നുപോകാനോ അല്ലെങ്കിൽfinally
ബ്ലോക്കിനുള്ളിലെ പിശകുകൾ തെറ്റായി കൈകാര്യം ചെയ്യാനോ എളുപ്പമാണ്. - നെസ്റ്റിംഗ് സങ്കീർണ്ണത: ഒന്നിലധികം റിസോഴ്സുകൾ കൈകാര്യം ചെയ്യുന്നത് ആഴത്തിൽ നെസ്റ്റ് ചെയ്ത
try...finally
ബ്ലോക്കുകളിലേക്ക് നയിക്കുന്നു, ഇതിനെ പലപ്പോഴും "പിരമിഡ് ഓഫ് ഡൂം" എന്ന് വിളിക്കാറുണ്ട്.
ഒരു ആധുനിക പരിഹാരം: TC39 'using' ഡിക്ലറേഷൻ പ്രൊപ്പോസൽ
ഈ പോരായ്മകൾ പരിഹരിക്കുന്നതിനായി, TC39 കമ്മിറ്റി (ജാവാസ്ക്രിപ്റ്റ് സ്റ്റാൻഡേർഡ് ചെയ്യുന്ന) എക്സ്പ്ലിസിറ്റ് റിസോഴ്സ് മാനേജ്മെന്റ് പ്രൊപ്പോസൽ മുന്നോട്ട് വെച്ചിട്ടുണ്ട്. നിലവിൽ സ്റ്റേജ് 3-ൽ ഉള്ള ഈ പ്രൊപ്പോസൽ (അതായത് ഇത് ECMAScript സ്റ്റാൻഡേർഡിൽ ഉൾപ്പെടുത്താനുള്ള ഒരു സ്ഥാനാർത്ഥിയാണ്), രണ്ട് പുതിയ കീവേഡുകൾ അവതരിപ്പിക്കുന്നു—using
, await using
—കൂടാതെ ഒബ്ജക്റ്റുകൾക്ക് അവയുടെ സ്വന്തം ക്ലീനപ്പ് ലോജിക് നിർവചിക്കാനുള്ള ഒരു സംവിധാനവും.
ഈ പ്രൊപ്പോസലിന്റെ കാതൽ "ഡിസ്പോസിബിൾ" റിസോഴ്സ് എന്ന ആശയമാണ്. ഒരു പ്രത്യേക മെത്തേഡ് ഒരു വെൽ-നോൺ സിംബൽ കീ ഉപയോഗിച്ച് നടപ്പിലാക്കുന്നതിലൂടെ ഒരു ഒബ്ജക്റ്റ് ഡിസ്പോസിബിൾ ആകുന്നു:
[Symbol.dispose]()
: സിൻക്രണസ് ക്ലീനപ്പ് ലോജിക്കിനായി.[Symbol.asyncDispose]()
: അസിൻക്രണസ് ക്ലീനപ്പ് ലോജിക്കിനായി (ഉദാഹരണത്തിന്, ഒരു നെറ്റ്വർക്ക് കണക്ഷൻ ക്ലോസ് ചെയ്യുന്നത്).
നിങ്ങൾ using
അല്ലെങ്കിൽ await using
ഉപയോഗിച്ച് ഒരു വേരിയബിൾ ഡിക്ലയർ ചെയ്യുമ്പോൾ, ആ വേരിയബിൾ സ്കോപ്പിൽ നിന്ന് പുറത്തുപോകുമ്പോൾ, അതായത് ബ്ലോക്കിന്റെ അവസാനത്തിലോ അല്ലെങ്കിൽ ഒരു പിശക് സംഭവിച്ചാലോ, ജാവാസ്ക്രിപ്റ്റ് സ്വയമേവ അതിന്റെ അനുബന്ധ ഡിസ്പോസ് മെത്തേഡ് വിളിക്കുന്നു.
നമുക്ക് ഒരു ഡിസ്പോസിബിൾ ഡാറ്റാബേസ് കണക്ഷൻ റാപ്പർ ഉണ്ടാക്കാം:
class ManagedDatabaseConnection {
constructor(connection) {
this.connection = connection;
this.isDisposed = false;
}
// Expose database methods like query
async query(sql, params) {
if (this.isDisposed) {
throw new Error("Connection is already disposed.");
}
return this.connection.query(sql, params);
}
async [Symbol.asyncDispose]() {
if (!this.isDisposed) {
console.log('Disposing connection...');
await this.connection.close();
this.isDisposed = true;
console.log('Connection disposed.');
}
}
}
// How to use it:
async function getUserByIdWithUsing(id) {
// Assumes getRawConnection returns a promise for a connection object
const rawConnection = await getRawConnection();
await using connection = new ManagedDatabaseConnection(rawConnection);
const result = await connection.query('SELECT * FROM users WHERE id = ?', [id]);
return result[0];
// No finally block needed! `connection[Symbol.asyncDispose]` is called automatically here.
}
വ്യത്യാസം നോക്കൂ! കോഡിന്റെ ഉദ്ദേശ്യം സ്ഫടികം പോലെ വ്യക്തമാണ്. ബിസിനസ്സ് ലോജിക് മുന്നിലും കേന്ദ്രത്തിലുമാണ്, റിസോഴ്സ് മാനേജ്മെന്റ് സ്വയമേവയും വിശ്വസനീയമായും తెరശ്ശീലയ്ക്ക് പിന്നിൽ കൈകാര്യം ചെയ്യപ്പെടുന്നു. കോഡിന്റെ വ്യക്തതയിലും സുരക്ഷയിലും ഇത് ഒരു വലിയ പുരോഗതിയാണ്.
പൂളിംഗിന്റെ ശക്തി: പുനരുപയോഗിക്കാമെങ്കിൽ എന്തിന് വീണ്ടും നിർമ്മിക്കണം?
using
പാറ്റേൺ *ഉറപ്പായ ക്ലീനപ്പ്* എന്ന പ്രശ്നം പരിഹരിക്കുന്നു. എന്നാൽ ഉയർന്ന ട്രാഫിക്കുള്ള ഒരു ആപ്ലിക്കേഷനിൽ, ഓരോ അഭ്യർത്ഥനയ്ക്കും ഒരു ഡാറ്റാബേസ് കണക്ഷൻ ഉണ്ടാക്കുകയും നശിപ്പിക്കുകയും ചെയ്യുന്നത് അങ്ങേയറ്റം കാര്യക്ഷമമല്ലാത്ത ഒന്നാണ്. ഇവിടെയാണ് റിസോഴ്സ് പൂളിംഗ് പ്രസക്തമാകുന്നത്.
എന്താണ് ഒരു റിസോഴ്സ് പൂൾ?
ഉപയോഗിക്കാൻ തയ്യാറായ റിസോഴ്സുകളുടെ ഒരു കാഷെ പരിപാലിക്കുന്ന ഒരു ഡിസൈൻ പാറ്റേൺ ആണ് റിസോഴ്സ് പൂൾ. ഒരു ലൈബ്രറിയിലെ പുസ്തക ശേഖരം പോലെ ഇതിനെ കരുതാം. വായിക്കാൻ തോന്നുമ്പോഴെല്ലാം പുതിയ പുസ്തകം വാങ്ങി വായിച്ചശേഷം വലിച്ചെറിയുന്നതിന് പകരം, ലൈബ്രറിയിൽ നിന്ന് ഒന്ന് കടമെടുത്ത് വായിച്ച് മറ്റൊരാൾക്ക് ഉപയോഗിക്കാനായി തിരികെ നൽകുന്നു. ഇത് വളരെ കാര്യക്ഷമമാണ്.
ഒരു സാധാരണ റിസോഴ്സ് പൂൾ നടപ്പിലാക്കുന്നതിൽ താഴെ പറയുന്നവ ഉൾപ്പെടുന്നു:
- ആരംഭിക്കൽ: പൂൾ ഒരു മിനിമം, മാക്സിമം എണ്ണം റിസോഴ്സുകളോടെയാണ് സൃഷ്ടിക്കുന്നത്. ഇത് മിനിമം എണ്ണം റിസോഴ്സുകൾ മുൻകൂട്ടി തയ്യാറാക്കിയേക്കാം.
- നേടൽ: ഒരു ക്ലയിന്റ് പൂളിൽ നിന്ന് ഒരു റിസോഴ്സ് അഭ്യർത്ഥിക്കുന്നു. ഒരു റിസോഴ്സ് ലഭ്യമാണെങ്കിൽ, പൂൾ അത് നൽകുന്നു. ഇല്ലെങ്കിൽ, ക്ലയിന്റിന് ഒന്ന് ലഭ്യമാകുന്നതുവരെ കാത്തിരിക്കേണ്ടി വന്നേക്കാം, അല്ലെങ്കിൽ പൂൾ അതിന്റെ പരമാവധി പരിധിക്ക് താഴെയാണെങ്കിൽ പുതിയൊരെണ്ണം ഉണ്ടാക്കിയേക്കാം.
- തിരികെ നൽകൽ: ക്ലയിന്റിന്റെ ഉപയോഗം കഴിഞ്ഞാൽ, അത് റിസോഴ്സിനെ നശിപ്പിക്കുന്നതിന് പകരം പൂളിലേക്ക് തിരികെ നൽകുന്നു. പൂളിന് ഈ റിസോഴ്സ് മറ്റൊരു ക്ലയിന്റിന് നൽകാൻ കഴിയും.
- നശിപ്പിക്കൽ: ആപ്ലിക്കേഷൻ ഷട്ട് ഡൗൺ ചെയ്യുമ്പോൾ, പൂൾ അത് കൈകാര്യം ചെയ്യുന്ന എല്ലാ റിസോഴ്സുകളും ഭംഗിയായി ക്ലോസ് ചെയ്യുന്നു.
പൂളിംഗിന്റെ പ്രയോജനങ്ങൾ
- കുറഞ്ഞ ലേറ്റൻസി: ഒരു പൂളിൽ നിന്ന് റിസോഴ്സ് നേടുന്നത് പുതിയൊരെണ്ണം ഉണ്ടാക്കുന്നതിനേക്കാൾ വളരെ വേഗതയേറിയതാണ്.
- കുറഞ്ഞ ഓവർഹെഡ്: നിങ്ങളുടെ ആപ്ലിക്കേഷൻ സെർവറിലും ബാഹ്യ സിസ്റ്റത്തിലും (ഉദാഹരണത്തിന്, ഡാറ്റാബേസ്) ഉള്ള സിപിയു, മെമ്മറി സമ്മർദ്ദം കുറയ്ക്കുന്നു.
- കണക്ഷൻ ത്രോട്ടിലിംഗ്: ഒരു പരമാവധി പൂൾ വലുപ്പം സജ്ജീകരിക്കുന്നതിലൂടെ, നിങ്ങളുടെ ആപ്ലിക്കേഷൻ ഒരേസമയം വളരെയധികം കണക്ഷനുകൾ ഉപയോഗിച്ച് ഒരു ഡാറ്റാബേസിനെയോ ബാഹ്യ സേവനത്തെയോ അമിതമായി ഭാരപ്പെടുത്തുന്നത് തടയുന്നു.
മഹത്തായ സമന്വയം: `using`-നെ ഒരു റിസോഴ്സ് പൂളുമായി സംയോജിപ്പിക്കുന്നു
ഇപ്പോൾ നമ്മൾ നമ്മുടെ തന്ത്രത്തിന്റെ കാതലിലേക്ക് എത്തുന്നു. ഉറപ്പായ ക്ലീനപ്പിനായി നമുക്ക് ഒരു മികച്ച പാറ്റേണും (using
) പ്രകടനത്തിനായി തെളിയിക്കപ്പെട്ട ഒരു തന്ത്രവും (പൂളിംഗ്) ഉണ്ട്. ഇവയെ എങ്ങനെ തടസ്സങ്ങളില്ലാത്ത, കരുത്തുറ്റ ഒരു പരിഹാരത്തിലേക്ക് ലയിപ്പിക്കാം?
പൂളിൽ നിന്ന് ഒരു റിസോഴ്സ് നേടുകയും, ഉപയോഗം കഴിയുമ്പോൾ, പിശകുകൾ ഉണ്ടായാൽ പോലും, അത് പൂളിലേക്ക് തിരികെ നൽകുമെന്ന് ഉറപ്പാക്കുക എന്നതാണ് ലക്ഷ്യം. ഡിസ്പോസ് പ്രോട്ടോക്കോൾ നടപ്പിലാക്കുന്ന ഒരു റാപ്പർ ഒബ്ജക്റ്റ് ഉണ്ടാക്കി നമുക്കിത് നേടാൻ കഴിയും, എന്നാൽ അതിന്റെ `dispose` മെത്തേഡ് `resource.close()` എന്നതിന് പകരം `pool.release()` എന്ന് വിളിക്കുന്നു.
ഇതാണ് മാന്ത്രികമായ കണ്ണി: `dispose` പ്രവർത്തനം 'നശിപ്പിക്കുക' എന്നതിന് പകരം 'പൂളിലേക്ക് മടങ്ങുക' എന്നായി മാറുന്നു.
ഘട്ടം ഘട്ടമായുള്ള നിർമ്മാണം
ഇത് പ്രവർത്തിക്കുന്നതിന് ആവശ്യമായ ഒരു പൊതുവായ റിസോഴ്സ് പൂളും റാപ്പറുകളും നമുക്ക് നിർമ്മിക്കാം.
ഘട്ടം 1: ലളിതവും പൊതുവായതുമായ ഒരു റിസോഴ്സ് പൂൾ നിർമ്മിക്കുന്നു
ഒരു അസിൻക്രണസ് റിസോഴ്സ് പൂളിന്റെ ഒരു ആശയപരമായ നിർമ്മാണം താഴെ നൽകുന്നു. ഒരു പ്രൊഡക്ഷൻ-റെഡി പതിപ്പിന് ടൈംഔട്ടുകൾ, ഉപയോഗിക്കാത്ത റിസോഴ്സുകൾ ഒഴിവാക്കൽ, റീട്രൈ ലോജിക് തുടങ്ങിയ കൂടുതൽ ഫീച്ചറുകൾ ഉണ്ടാകും, എന്നാൽ ഇത് പ്രധാന മെക്കാനിക്സ് വ്യക്തമാക്കുന്നു.
class ResourcePool {
constructor({ create, destroy, min, max }) {
this.factory = { create, destroy };
this.config = { min, max };
this.pool = []; // Stores available resources
this.active = []; // Stores resources currently in use
this.waitQueue = []; // Stores promises for clients waiting for a resource
// Initialize minimum resources
for (let i = 0; i < this.config.min; i++) {
this._createResource().then(resource => this.pool.push(resource));
}
}
async _createResource() {
const resource = await this.factory.create();
return resource;
}
async acquire() {
// If a resource is available in the pool, use it
if (this.pool.length > 0) {
const resource = this.pool.pop();
this.active.push(resource);
return resource;
}
// If we are under the max limit, create a new one
if (this.active.length < this.config.max) {
const resource = await this._createResource();
this.active.push(resource);
return resource;
}
// Otherwise, wait for a resource to be released
return new Promise((resolve, reject) => {
// A real implementation would have a timeout here
this.waitQueue.push({ resolve, reject });
});
}
release(resource) {
// Check if someone is waiting
if (this.waitQueue.length > 0) {
const waiter = this.waitQueue.shift();
// Give this resource directly to the waiting client
waiter.resolve(resource);
} else {
// Otherwise, return it to the pool
this.pool.push(resource);
}
// Remove from active list
this.active = this.active.filter(r => r !== resource);
}
async close() {
// Close all resources in the pool and those active
const allResources = [...this.pool, ...this.active];
this.pool = [];
this.active = [];
await Promise.all(allResources.map(r => this.factory.destroy(r)));
}
}
ഘട്ടം 2: 'PooledResource' റാപ്പർ ഉണ്ടാക്കുന്നു
പൂളിനെ using
സിന്റാക്സുമായി ബന്ധിപ്പിക്കുന്ന നിർണായക ഭാഗമാണിത്. ഇത് ഒരു റിസോഴ്സിനെയും അത് വന്ന പൂളിന്റെ ഒരു റഫറൻസിനെയും സൂക്ഷിക്കും. അതിന്റെ ഡിസ്പോസ് മെത്തേഡ് pool.release()
എന്ന് വിളിക്കും.
class PooledResource {
constructor(resource, pool) {
this.resource = resource;
this.pool = pool;
this._isReleased = false;
}
// This method releases the resource back to the pool
[Symbol.dispose]() {
if (this._isReleased) {
return;
}
this.pool.release(this.resource);
this._isReleased = true;
console.log('Resource released back to pool.');
}
}
// We can also create an async version
class AsyncPooledResource {
constructor(resource, pool) {
this.resource = resource;
this.pool = pool;
this._isReleased = false;
}
// The dispose method can be async if releasing is an async operation
async [Symbol.asyncDispose]() {
if (this._isReleased) {
return;
}
// In our simple pool, release is sync, but we show the pattern
await Promise.resolve(this.pool.release(this.resource));
this._isReleased = true;
console.log('Async resource released back to pool.');
}
}
ഘട്ടം 3: എല്ലാം ഒരു ഏകീകൃത മാനേജറിൽ ഒരുമിപ്പിക്കുന്നു
API കൂടുതൽ വൃത്തിയുള്ളതാക്കാൻ, പൂളിനെ എൻക്യാപ്സുലേറ്റ് ചെയ്യുകയും ഡിസ്പോസിബിൾ റാപ്പറുകൾ നൽകുകയും ചെയ്യുന്ന ഒരു മാനേജർ ക്ലാസ് നമുക്ക് ഉണ്ടാക്കാം.
class ResourceManager {
constructor(poolConfig) {
this.pool = new ResourcePool(poolConfig);
}
async getResource() {
const resource = await this.pool.acquire();
// Use the async wrapper if your resource cleanup could be async
return new AsyncPooledResource(resource, this.pool);
}
async shutdown() {
await this.pool.close();
}
}
// --- Example Usage ---
// 1. Define how to create and destroy our mock resources
let resourceIdCounter = 0;
const poolConfig = {
create: async () => {
resourceIdCounter++;
console.log(`Creating resource #${resourceIdCounter}...`);
return { id: resourceIdCounter, data: `data for ${resourceIdCounter}` };
},
destroy: async (resource) => {
console.log(`Destroying resource #${resource.id}...`);
},
min: 1,
max: 3
};
// 2. Create the manager
const manager = new ResourceManager(poolConfig);
// 3. Use the pattern in an application function
async function processRequest(requestId) {
console.log(`Request ${requestId}: Attempting to get a resource...`);
try {
await using client = await manager.getResource();
console.log(`Request ${requestId}: Acquired resource #${client.resource.id}. Working...`);
// Simulate some work
await new Promise(resolve => setTimeout(resolve, 500));
// Simulate a random failure
if (Math.random() > 0.7) {
throw new Error(`Request ${requestId}: Simulated random failure!`);
}
console.log(`Request ${requestId}: Work complete.`);
} catch (error) {
console.error(error.message);
}
// `client` is automatically released back to the pool here, in success or failure cases.
}
// --- Simulate concurrent requests ---
async function main() {
const requests = [
processRequest(1),
processRequest(2),
processRequest(3),
processRequest(4),
processRequest(5)
];
await Promise.all(requests);
console.log('\nAll requests finished. Shutting down pool...');
await manager.shutdown();
}
main();
നിങ്ങൾ ഈ കോഡ് പ്രവർത്തിപ്പിക്കുകയാണെങ്കിൽ (പ്രൊപ്പോസൽ പിന്തുണയ്ക്കുന്ന ഒരു ആധുനിക ടൈപ്പ്സ്ക്രിപ്റ്റ് അല്ലെങ്കിൽ ബേബൽ സെറ്റപ്പ് ഉപയോഗിച്ച്), റിസോഴ്സുകൾ പരമാവധി പരിധി വരെ ഉണ്ടാക്കുന്നതും, വിവിധ അഭ്യർത്ഥനകൾക്കായി പുനരുപയോഗിക്കുന്നതും, എപ്പോഴും പൂളിലേക്ക് തിരികെ നൽകുന്നതും നിങ്ങൾക്ക് കാണാൻ കഴിയും. `processRequest` ഫംഗ്ഷൻ വൃത്തിയുള്ളതും, അതിന്റെ ജോലിയിൽ ശ്രദ്ധ കേന്ദ്രീകരിക്കുന്നതും, റിസോഴ്സ് ക്ലീനപ്പിന്റെ ഉത്തരവാദിത്തത്തിൽ നിന്ന് പൂർണ്ണമായും ഒഴിവായതുമാണ്.
ഒരു ആഗോള പ്രേക്ഷകർക്കുള്ള വിപുലമായ പരിഗണനകളും മികച്ച പരിശീലനങ്ങളും
നമ്മുടെ ഉദാഹരണം ഒരു ശക്തമായ അടിത്തറ നൽകുന്നുണ്ടെങ്കിലും, യഥാർത്ഥ ലോകത്തിലെ, ആഗോളമായി വിതരണം ചെയ്യപ്പെട്ട ആപ്ലിക്കേഷനുകൾക്ക് കൂടുതൽ സൂക്ഷ്മമായ പരിഗണനകൾ ആവശ്യമാണ്.
കൺകറൻസിയും പൂൾ സൈസ് ട്യൂണിംഗും
`min`, `max` പൂൾ വലുപ്പങ്ങൾ നിർണ്ണായകമായ ട്യൂണിംഗ് പാരാമീറ്ററുകളാണ്. ഇതിന് ഒരു പ്രത്യേക മാന്ത്രിക സംഖ്യയില്ല; ഒപ്റ്റിമൽ വലുപ്പം നിങ്ങളുടെ ആപ്ലിക്കേഷന്റെ ലോഡ്, റിസോഴ്സ് ഉണ്ടാക്കുന്നതിനുള്ള ലേറ്റൻസി, ബാക്കെൻഡ് സേവനത്തിന്റെ പരിധികൾ (ഉദാഹരണത്തിന്, നിങ്ങളുടെ ഡാറ്റാബേസിന്റെ പരമാവധി കണക്ഷനുകൾ) എന്നിവയെ ആശ്രയിച്ചിരിക്കുന്നു.
- വളരെ ചെറുതാണെങ്കിൽ: നിങ്ങളുടെ ആപ്ലിക്കേഷൻ ത്രെഡുകൾ ഒരു റിസോഴ്സ് ലഭ്യമാകാനായി വളരെയധികം സമയം കാത്തിരിക്കേണ്ടി വരും, ഇത് ഒരു പ്രകടന തടസ്സം സൃഷ്ടിക്കും. ഇതിനെ പൂൾ കണ്ടൻഷൻ എന്ന് പറയുന്നു.
- വളരെ വലുതാണെങ്കിൽ: നിങ്ങളുടെ ആപ്ലിക്കേഷൻ സെർവറിലും ബാക്കെൻഡിലും നിങ്ങൾ അധിക മെമ്മറിയും സിപിയുവും ഉപയോഗിക്കും. ഒരു ആഗോളതലത്തിൽ വിതരണം ചെയ്യപ്പെട്ട ടീമിനായി, ഈ സംഖ്യകൾക്ക് പിന്നിലെ കാരണം രേഖപ്പെടുത്തേണ്ടത് അത്യാവശ്യമാണ്, ഒരുപക്ഷേ ലോഡ് ടെസ്റ്റിംഗ് ഫലങ്ങളെ അടിസ്ഥാനമാക്കി, അതുവഴി വിവിധ പ്രദേശങ്ങളിലെ എഞ്ചിനീയർമാർക്ക് പരിമിതികൾ മനസ്സിലാക്കാൻ കഴിയും.
പ്രതീക്ഷിക്കുന്ന ലോഡിനെ അടിസ്ഥാനമാക്കി ചെറിയ സംഖ്യകളിൽ നിന്ന് ആരംഭിച്ച്, പൂൾ കാത്തിരിപ്പ് സമയവും ഉപയോഗവും അളക്കാൻ ആപ്ലിക്കേഷൻ പെർഫോമൻസ് മോണിറ്ററിംഗ് (APM) ടൂളുകൾ ഉപയോഗിക്കുക. അതനുസരിച്ച് ക്രമീകരിക്കുക.
ടൈംഔട്ടും എറർ ഹാൻഡ്ലിംഗും
പൂൾ അതിന്റെ പരമാവധി വലുപ്പത്തിലായിരിക്കുകയും എല്ലാ റിസോഴ്സുകളും ഉപയോഗത്തിലായിരിക്കുകയും ചെയ്താൽ എന്ത് സംഭവിക്കും? നമ്മുടെ ലളിതമായ പൂൾ പുതിയ അഭ്യർത്ഥനകളെ എക്കാലവും കാത്തിരിപ്പിക്കും. ഒരു പ്രൊഡക്ഷൻ-ഗ്രേഡ് പൂളിന് ഒരു അക്വിസിഷൻ ടൈംഔട്ട് ഉണ്ടായിരിക്കണം. ഒരു നിശ്ചിത സമയത്തിനുള്ളിൽ (ഉദാഹരണത്തിന്, 30 സെക്കൻഡ്) ഒരു റിസോഴ്സ് നേടാൻ കഴിഞ്ഞില്ലെങ്കിൽ, `acquire` കോൾ ഒരു ടൈംഔട്ട് പിശകോടെ പരാജയപ്പെടണം. ഇത് അഭ്യർത്ഥനകൾ അനിശ്ചിതമായി തൂങ്ങിക്കിടക്കുന്നത് തടയുകയും, ഒരുപക്ഷേ ക്ലയിന്റിന് ഒരു `503 സർവീസ് ലഭ്യമല്ല` എന്ന സ്റ്റാറ്റസ് നൽകി ഭംഗിയായി പരാജയപ്പെടാൻ നിങ്ങളെ അനുവദിക്കുകയും ചെയ്യുന്നു.
കൂടാതെ, പൂൾ പഴകിയതോ കേടായതോ ആയ റിസോഴ്സുകൾ കൈകാര്യം ചെയ്യണം. ഒരു റിസോഴ്സ് നൽകുന്നതിന് മുമ്പ് അത് ഇപ്പോഴും സാധുവാണോ എന്ന് പരിശോധിക്കാൻ കഴിയുന്ന ഒരു വാലിഡേഷൻ മെക്കാനിസം (ഉദാഹരണത്തിന്, ഒരു `testOnBorrow` ഫംഗ്ഷൻ) അതിന് ഉണ്ടായിരിക്കണം. അത് കേടായതാണെങ്കിൽ, പൂൾ അത് നശിപ്പിക്കുകയും പകരം പുതിയൊരെണ്ണം ഉണ്ടാക്കുകയും വേണം.
ഫ്രെയിംവർക്കുകളും ആർക്കിടെക്ചറുകളുമായുള്ള സംയോജനം
ഈ റിസോഴ്സ് മാനേജ്മെന്റ് പാറ്റേൺ ഒരു ഒറ്റപ്പെട്ട സാങ്കേതിക വിദ്യയല്ല; ഇത് ഒരു വലിയ ആർക്കിടെക്ചറിന്റെ അടിസ്ഥാന ഭാഗമാണ്.
- ഡിപെൻഡൻസി ഇഞ്ചക്ഷൻ (DI): നമ്മൾ ഉണ്ടാക്കിയ `ResourceManager` ഒരു DI കണ്ടെയ്നറിലെ ഒരു സിംഗിൾടൺ സേവനത്തിന് അനുയോജ്യമായ ഒരു സ്ഥാനാർത്ഥിയാണ്. എല്ലായിടത്തും ഒരു പുതിയ മാനേജർ ഉണ്ടാക്കുന്നതിനു പകരം, നിങ്ങളുടെ ആപ്ലിക്കേഷനിലുടനീളം ഒരേ ഇൻസ്റ്റൻസ് നിങ്ങൾ ഇൻജെക്റ്റ് ചെയ്യുന്നു, എല്ലാവരും ഒരേ പൂൾ പങ്കിടുന്നുവെന്ന് ഉറപ്പാക്കുന്നു.
- മൈക്രോസർവീസുകൾ: ഒരു മൈക്രോസർവീസ് ആർക്കിടെക്ചറിൽ, ഓരോ സർവീസ് ഇൻസ്റ്റൻസും ഡാറ്റാബേസുകളിലേക്കോ മറ്റ് സേവനങ്ങളിലേക്കോ ഉള്ള കണക്ഷനുകളുടെ സ്വന്തം പൂൾ കൈകാര്യം ചെയ്യും. ഇത് പരാജയങ്ങളെ ഒറ്റപ്പെടുത്തുകയും ഓരോ സേവനത്തെയും സ്വതന്ത്രമായി ട്യൂൺ ചെയ്യാൻ അനുവദിക്കുകയും ചെയ്യുന്നു.
- സെർവർലെസ്സ് (FaaS): AWS ലാംഡ അല്ലെങ്കിൽ ഗൂഗിൾ ക്ലൗഡ് ഫംഗ്ഷൻസ് പോലുള്ള പ്ലാറ്റ്ഫോമുകളിൽ, ഫംഗ്ഷനുകളുടെ സ്റ്റേറ്റ്ലെസ്സ്, ഹ്രസ്വകാല സ്വഭാവം കാരണം കണക്ഷനുകൾ കൈകാര്യം ചെയ്യുന്നത് വളരെ ബുദ്ധിമുട്ടാണ്. ഫംഗ്ഷൻ ഇൻവോക്കേഷനുകൾക്കിടയിൽ നിലനിൽക്കുന്ന ഒരു ഗ്ലോബൽ കണക്ഷൻ മാനേജർ (ഹാൻഡ്ലറിന് പുറത്തുള്ള ഗ്ലോബൽ സ്കോപ്പ് ഉപയോഗിച്ച്) ഹാൻഡ്ലറിനുള്ളിലെ ഈ `using`/പൂൾ പാറ്റേണുമായി സംയോജിപ്പിക്കുന്നത് നിങ്ങളുടെ ഡാറ്റാബേസിനെ അമിതമായി ഭാരപ്പെടുത്തുന്നത് ഒഴിവാക്കാനുള്ള സ്റ്റാൻഡേർഡ് മികച്ച പരിശീലനമാണ്.
ഉപസംഹാരം: കൂടുതൽ വൃത്തിയുള്ളതും സുരക്ഷിതവും മികച്ച പ്രകടനമുള്ളതുമായ ജാവാസ്ക്രിപ്റ്റ് എഴുതുന്നു
ഫലപ്രദമായ റിസോഴ്സ് മാനേജ്മെന്റ് പ്രൊഫഷണൽ സോഫ്റ്റ്വെയർ എഞ്ചിനീയറിംഗിന്റെ ഒരു മുഖമുദ്രയാണ്. മാനുവൽ ആയതും പലപ്പോഴും വിരസവുമായ try...finally
പാറ്റേണിൽ നിന്ന് മുന്നോട്ട് പോകുന്നതിലൂടെ, നമുക്ക് കൂടുതൽ പ്രതിരോധശേഷിയുള്ളതും, മികച്ച പ്രകടനമുള്ളതും, വളരെ വായിക്കാൻ എളുപ്പമുള്ളതുമായ കോഡ് എഴുതാൻ കഴിയും.
നമ്മൾ പര്യവേക്ഷണം ചെയ്ത ശക്തമായ തന്ത്രം നമുക്ക് പുനരാവിഷ്കരിക്കാം:
- പ്രശ്നം: ഡാറ്റാബേസ് കണക്ഷനുകൾ പോലുള്ള ചെലവേറിയതും പരിമിതവുമായ ബാഹ്യ റിസോഴ്സുകൾ കൈകാര്യം ചെയ്യുന്നത് സങ്കീർണ്ണമാണ്. ഡിറ്റർമിനിസ്റ്റിക് ക്ലീനപ്പിനായി ഗാർബേജ് കളക്ടറെ ആശ്രയിക്കുന്നത് ഒരു ഓപ്ഷനല്ല, കൂടാതെ
try...finally
ഉപയോഗിച്ചുള്ള മാനുവൽ മാനേജ്മെന്റ് ദൈർഘ്യമേറിയതും പിശകുകൾക്ക് സാധ്യതയുള്ളതുമാണ്. - സുരക്ഷാ വലയം: TC39 എക്സ്പ്ലിസിറ്റ് റിസോഴ്സ് മാനേജ്മെന്റ് പ്രൊപ്പോസലിന്റെ ഭാഗമായ, വരാനിരിക്കുന്ന
using
,await using
സിന്റാക്സ്, ഒരു റിസോഴ്സിന്റെ ക്ലീനപ്പ് ലോജിക് എപ്പോഴും നടപ്പിലാക്കുമെന്ന് ഉറപ്പാക്കുന്നതിന് ഒരു ഡിക്ലറേറ്റീവും മിക്കവാറും പിശകുകളില്ലാത്തതുമായ മാർഗ്ഗം നൽകുന്നു. - പെർഫോമൻസ് എഞ്ചിൻ: നിലവിലുള്ള റിസോഴ്സുകൾ പുനരുപയോഗിക്കുന്നതിലൂടെ റിസോഴ്സ് സൃഷ്ടിക്കുന്നതിനും നശിപ്പിക്കുന്നതിനുമുള്ള ഉയർന്ന ചെലവ് ഒഴിവാക്കുന്ന, കാലം തെളിയിച്ച ഒരു പാറ്റേണാണ് റിസോഴ്സ് പൂളിംഗ്.
- സമന്വയം: ഡിസ്പോസ് പ്രോട്ടോക്കോൾ (
[Symbol.dispose]
അല്ലെങ്കിൽ[Symbol.asyncDispose]
) നടപ്പിലാക്കുകയും, അതിന്റെ ക്ലീനപ്പ് ലോജിക് ഒരു റിസോഴ്സിനെ അതിന്റെ പൂളിലേക്ക് തിരികെ നൽകുക എന്നതാവുകയും ചെയ്യുന്ന ഒരു റാപ്പർ ഉണ്ടാക്കുന്നതിലൂടെ, നമ്മൾ രണ്ട് ലോകങ്ങളിലെയും മികച്ചത് നേടുന്നു.using
സ്റ്റേറ്റ്മെന്റിന്റെ സുരക്ഷയും ചാരുതയും സഹിതം പൂളിംഗിന്റെ പ്രകടനം നമുക്ക് ലഭിക്കുന്നു.
ഉയർന്ന പ്രകടനശേഷിയുള്ള, വലിയ തോതിലുള്ള സിസ്റ്റങ്ങൾ നിർമ്മിക്കുന്നതിനുള്ള ഒരു പ്രധാന ഭാഷയായി ജാവാസ്ക്രിപ്റ്റ് വളരുന്നത് തുടരുമ്പോൾ, ഇതുപോലുള്ള പാറ്റേണുകൾ സ്വീകരിക്കുന്നത് ഇനി ഒരു ഓപ്ഷനല്ല. ആഗോള പ്രേക്ഷകർക്കായി കരുത്തുറ്റതും, വികസിപ്പിക്കാവുന്നതും, പരിപാലിക്കാൻ എളുപ്പമുള്ളതുമായ അടുത്ത തലമുറ ആപ്ലിക്കേഷനുകൾ നമ്മൾ നിർമ്മിക്കുന്നത് ഇങ്ങനെയാണ്. ടൈപ്പ്സ്ക്രിപ്റ്റ് അല്ലെങ്കിൽ ബേബൽ വഴി നിങ്ങളുടെ പ്രോജക്റ്റുകളിൽ ഇന്ന് തന്നെ using
ഡിക്ലറേഷൻ ഉപയോഗിച്ച് പരീക്ഷിക്കാൻ ആരംഭിക്കുക, നിങ്ങളുടെ റിസോഴ്സ് മാനേജ്മെന്റ് വ്യക്തതയോടെയും ആത്മവിശ്വാസത്തോടെയും രൂപകൽപ്പന ചെയ്യുക.