ഇടനിലയിലുള്ള അറേകളെ ഒഴിവാക്കി, ലേസി ഇവാലുവേഷനിലൂടെ മികച്ച പ്രകടനം നൽകുന്ന ജാവാസ്ക്രിപ്റ്റ് ഇറ്ററേറ്റർ ഹെൽപ്പറുകൾ ഡാറ്റാ പ്രോസസ്സിംഗിൽ എങ്ങനെ വിപ്ലവം സൃഷ്ടിക്കുന്നുവെന്ന് കണ്ടെത്തുക.
ജാവസ്ക്രിപ്റ്റിന്റെ പ്രകടന മികവിലെ അടുത്ത കുതിപ്പ്: ഇറ്ററേറ്റർ ഹെൽപ്പർ സ്ട്രീം ഫ്യൂഷനിലേക്കൊരു ആഴത്തിലുള്ള വിശകലനം
സോഫ്റ്റ്വെയർ വികസനത്തിന്റെ ലോകത്ത്, മികച്ച പ്രകടനത്തിനായുള്ള അന്വേഷണം ഒരു നിരന്തരമായ യാത്രയാണ്. ജാവസ്ക്രിപ്റ്റ് ഡെവലപ്പർമാരെ സംബന്ധിച്ചിടത്തോളം, ഡാറ്റ കൈകാര്യം ചെയ്യുന്നതിനുള്ള ഒരു സാധാരണവും ലളിതവുമായ രീതി .map(), .filter(), .reduce() പോലുള്ള അറേ മെത്തേഡുകൾ ഒരുമിച്ച് ഉപയോഗിക്കുന്നതാണ്. ഈ ഫ്ലൂയിന്റ് എപിഐ വായിക്കാനും മനസ്സിലാക്കാനും എളുപ്പമുള്ളതാണെങ്കിലും, ഇത് ഒരു വലിയ പ്രകടന തടസ്സത്തെ മറച്ചുവെക്കുന്നു: ഇടനിലയിലുള്ള അറേകളുടെ (intermediate arrays) രൂപീകരണം. ഈ ശൃംഖലയിലെ ഓരോ ഘട്ടവും ഒരു പുതിയ അറേ ഉണ്ടാക്കുകയും, മെമ്മറിയും സിപിയു സൈക്കിളുകളും ഉപയോഗിക്കുകയും ചെയ്യുന്നു. വലിയ ഡാറ്റാസെറ്റുകളിൽ, ഇത് പ്രകടനത്തിൽ വലിയൊരു ദുരന്തമായി മാറിയേക്കാം.
ഇവിടെയാണ് TC39 ഇറ്ററേറ്റർ ഹെൽപ്പേഴ്സ് പ്രൊപ്പോസൽ വരുന്നത്. ജാവാസ്ക്രിപ്റ്റിൽ ഡാറ്റയുടെ ശേഖരങ്ങൾ നമ്മൾ കൈകാര്യം ചെയ്യുന്ന രീതിയെ പുനർനിർവചിക്കാൻ പോകുന്ന എക്മാസ്ക്രിപ്റ്റ് (ECMAScript) സ്റ്റാൻഡേർഡിലേക്കുള്ള ഒരു വിപ്ലവകരമായ കൂട്ടിച്ചേർക്കലാണിത്. സ്ട്രീം ഫ്യൂഷൻ (അല്ലെങ്കിൽ ഓപ്പറേഷൻ ഫ്യൂഷൻ) എന്നറിയപ്പെടുന്ന ശക്തമായ ഒരു ഒപ്റ്റിമൈസേഷൻ ടെക്നിക്കാണ് ഇതിന്റെ കാതൽ. ഈ ലേഖനം ഈ പുതിയ രീതിയെക്കുറിച്ച് വിശദമായി പ്രതിപാദിക്കുന്നു. ഇത് എങ്ങനെ പ്രവർത്തിക്കുന്നു, എന്തിനാണ് ഇത് പ്രാധാന്യമർഹിക്കുന്നത്, കൂടുതൽ കാര്യക്ഷമവും മെമ്മറി-ഫ്രണ്ട്ലിയും ശക്തവുമായ കോഡ് എഴുതാൻ ഡെവലപ്പർമാരെ ഇത് എങ്ങനെ ശാക്തീകരിക്കും എന്നും ഇവിടെ വിശദീകരിക്കുന്നു.
പരമ്പരാഗത ചെയിനിംഗിലെ പ്രശ്നം: ഇടനിലയിലുള്ള അറേകളുടെ ഒരു കഥ
ഇറ്ററേറ്റർ ഹെൽപ്പറുകളുടെ പുതുമ പൂർണ്ണമായി മനസ്സിലാക്കാൻ, നിലവിലെ അറേ-അടിസ്ഥാനമാക്കിയുള്ള സമീപനത്തിന്റെ പരിമിതികൾ നമ്മൾ ആദ്യം മനസ്സിലാക്കണം. ഒരു ലളിതമായ, ദൈനംദിന ടാസ്ക് പരിഗണിക്കാം: ഒരു സംഖ്യകളുടെ ലിസ്റ്റിൽ നിന്ന്, ആദ്യത്തെ അഞ്ച് ഇരട്ട സംഖ്യകൾ കണ്ടെത്തി, അവയെ ഇരട്ടിയാക്കി, ഫലം ശേഖരിക്കണം.
സാധാരണ സമീപനം
സാധാരണ അറേ മെത്തേഡുകൾ ഉപയോഗിക്കുമ്പോൾ കോഡ് വളരെ വ്യക്തവും ലളിതവുമാണ്:
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, ...]; // വളരെ വലിയൊരു അറേ സങ്കൽപ്പിക്കുക
const result = numbers
.filter(n => n % 2 === 0) // ഘട്ടം 1: ഇരട്ട സംഖ്യകൾക്കായി ഫിൽട്ടർ ചെയ്യുക
.map(n => n * 2) // ഘട്ടം 2: അവയെ ഇരട്ടിയാക്കുക
.slice(0, 5); // ഘട്ടം 3: ആദ്യത്തെ അഞ്ചെണ്ണം എടുക്കുക
ഈ കോഡ് വായിക്കാൻ വളരെ എളുപ്പമാണ്, എന്നാൽ numbers-ൽ ദശലക്ഷക്കണക്കിന് എലമെന്റുകൾ ഉണ്ടെങ്കിൽ ജാവസ്ക്രിപ്റ്റ് എഞ്ചിൻ എങ്ങനെയാണ് പ്രവർത്തിക്കുന്നതെന്ന് നോക്കാം.
- ആവർത്തനം 1 (
.filter()): എഞ്ചിൻnumbersഎന്ന മുഴുവൻ അറേയിലൂടെയും കടന്നുപോകുന്നു. ഇത് മെമ്മറിയിൽevenNumbersഎന്ന് വിളിക്കാവുന്ന ഒരു പുതിയ ഇടനില അറേ ഉണ്ടാക്കുന്നു, ടെസ്റ്റ് പാസാകുന്ന എല്ലാ സംഖ്യകളെയും അതിൽ സൂക്ഷിക്കുന്നു.numbers-ൽ ഒരു ദശലക്ഷം എലമെന്റുകൾ ഉണ്ടെങ്കിൽ, ഇത് ഏകദേശം 500,000 എലമെന്റുകളുള്ള ഒരു അറേ ആയിരിക്കാം. - ആവർത്തനം 2 (
.map()): എഞ്ചിൻ ഇപ്പോൾevenNumbersഎന്ന മുഴുവൻ അറേയിലൂടെയും കടന്നുപോകുന്നു. ഇത് മാപ്പിംഗ് ഓപ്പറേഷന്റെ ഫലം സംഭരിക്കാൻdoubledNumbersഎന്ന് വിളിക്കാവുന്ന ഒരു രണ്ടാമത്തെ ഇടനില അറേ ഉണ്ടാക്കുന്നു. ഇതും 500,000 എലമെന്റുകളുള്ള മറ്റൊരു അറേ ആണ്. - ആവർത്തനം 3 (
.slice()): ഒടുവിൽ,doubledNumbers-ൽ നിന്ന് ആദ്യത്തെ അഞ്ച് എലമെന്റുകൾ എടുത്ത് എഞ്ചിൻ മൂന്നാമതൊരു അന്തിമ അറേ ഉണ്ടാക്കുന്നു.
മറഞ്ഞിരിക്കുന്ന പ്രത്യാഘാതങ്ങൾ
ഈ പ്രക്രിയ നിരവധി ഗുരുതരമായ പ്രകടന പ്രശ്നങ്ങൾ വെളിപ്പെടുത്തുന്നു:
- ഉയർന്ന മെമ്മറി ഉപയോഗം: നമ്മൾ രണ്ട് വലിയ താൽക്കാലിക അറകൾ ഉണ്ടാക്കി, അവ ഉടൻ തന്നെ ഉപേക്ഷിച്ചു. വളരെ വലിയ ഡാറ്റാസെറ്റുകളിൽ, ഇത് കാര്യമായ മെമ്മറി പ്രഷറിലേക്ക് നയിച്ചേക്കാം, ഇത് ആപ്ലിക്കേഷന്റെ വേഗത കുറയ്ക്കാനോ തകരാറിലാകാനോ ഇടയാക്കും.
- ഗാർബേജ് കളക്ഷൻ ഓവർഹെഡ്: നിങ്ങൾ കൂടുതൽ താൽക്കാലിക ഒബ്ജക്റ്റുകൾ ഉണ്ടാക്കുന്തോറും, ഗാർബേജ് കളക്ടറിന് അവ വൃത്തിയാക്കാൻ കൂടുതൽ കഠിനാധ്വാനം ചെയ്യേണ്ടിവരും, ഇത് പ്രകടനത്തിൽ തടസ്സങ്ങൾക്കും ഇടവേളകൾക്കും കാരണമാകും.
- പാഴായ കമ്പ്യൂട്ടേഷൻ: നമ്മൾ ദശലക്ഷക്കണക്കിന് എലമെന്റുകളിലൂടെ പലതവണ ആവർത്തിച്ചു. ഇതിലും മോശമായി, നമ്മുടെ അന്തിമ ലക്ഷ്യം അഞ്ച് ഫലങ്ങൾ മാത്രം നേടുക എന്നതായിരുന്നു. എന്നിട്ടും,
.filter(),.map()എന്നീ മെത്തേഡുകൾ മുഴുവൻ ഡാറ്റാസെറ്റും പ്രോസസ്സ് ചെയ്തു,.slice()മിക്ക ജോലികളും ഉപേക്ഷിക്കുന്നതിന് മുമ്പ് ദശലക്ഷക്കണക്കിന് അനാവശ്യ കണക്കുകൂട്ടലുകൾ നടത്തി.
ഇറ്ററേറ്റർ ഹെൽപ്പറുകളും സ്ട്രീം ഫ്യൂഷനും പരിഹരിക്കാൻ രൂപകൽപ്പന ചെയ്തിട്ടുള്ള അടിസ്ഥാനപരമായ പ്രശ്നം ഇതാണ്.
ഇറ്ററേറ്റർ ഹെൽപ്പറുകളെ പരിചയപ്പെടാം: ഡാറ്റാ പ്രോസസ്സിംഗിന് ഒരു പുതിയ മാതൃക
ഇറ്ററേറ്റർ ഹെൽപ്പേഴ്സ് പ്രൊപ്പോസൽ, നമുക്ക് പരിചിതമായ ഒരു കൂട്ടം മെത്തേഡുകൾ നേരിട്ട് Iterator.prototype-ലേക്ക് ചേർക്കുന്നു. ഇതിനർത്ഥം, ഒരു ഇറ്ററേറ്റർ ആയ ഏതൊരു ഒബ്ജക്റ്റിനും (ജനറേറ്ററുകൾ, Array.prototype.values() പോലുള്ള മെത്തേഡുകളുടെ ഫലം എന്നിവ ഉൾപ്പെടെ) ഈ ശക്തമായ പുതിയ ടൂളുകൾ ഉപയോഗിക്കാൻ കഴിയും.
ചില പ്രധാന മെത്തേഡുകൾ താഴെ പറയുന്നവയാണ്:
.map(mapperFn).filter(filterFn).take(limit).drop(limit).flatMap(mapperFn).reduce(reducerFn, initialValue).toArray().forEach(fn).some(fn).every(fn).find(fn)
നമ്മുടെ മുൻ ഉദാഹരണം ഈ പുതിയ ഹെൽപ്പറുകൾ ഉപയോഗിച്ച് വീണ്ടും എഴുതാം:
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, ...];
const result = numbers.values() // 1. അറേയിൽ നിന്ന് ഒരു ഇറ്ററേറ്റർ നേടുക
.filter(n => n % 2 === 0) // 2. ഒരു ഫിൽട്ടർ ഇറ്ററേറ്റർ ഉണ്ടാക്കുക
.map(n => n * 2) // 3. ഒരു മാപ്പ് ഇറ്ററേറ്റർ ഉണ്ടാക്കുക
.take(5) // 4. ഒരു ടേക്ക് ഇറ്ററേറ്റർ ഉണ്ടാക്കുക
.toArray(); // 5. ശൃംഖല പ്രവർത്തിപ്പിച്ച് ഫലങ്ങൾ ശേഖരിക്കുക
ആദ്യനോട്ടത്തിൽ, കോഡ് വളരെ സാമ്യമുള്ളതായി തോന്നുന്നു. പ്രധാന വ്യത്യാസം അതിന്റെ ആരംഭത്തിലാണ്—numbers.values()—ഇത് അറേയ്ക്ക് പകരം ഒരു ഇറ്ററേറ്റർ നൽകുന്നു, കൂടാതെ അവസാനത്തെ ഓപ്പറേഷൻ—.toArray()—അന്തിമ ഫലം ഉണ്ടാക്കാൻ ഇറ്ററേറ്ററിനെ ഉപയോഗിക്കുന്നു. എന്നാൽ യഥാർത്ഥ മാന്ത്രികത ഈ രണ്ട് ഘട്ടങ്ങൾക്കിടയിൽ സംഭവിക്കുന്നതിലാണ്.
ഈ ശൃംഖല ഇടനിലയിലുള്ള അറകൾ ഒന്നും തന്നെ ഉണ്ടാക്കുന്നില്ല. പകരം, ഇത് മുൻപത്തേതിനെ പൊതിഞ്ഞ് പുതിയതും കൂടുതൽ സങ്കീർണ്ണവുമായ ഒരു ഇറ്ററേറ്റർ നിർമ്മിക്കുന്നു. കമ്പ്യൂട്ടേഷൻ മാറ്റിവയ്ക്കപ്പെടുന്നു. .toArray() അല്ലെങ്കിൽ .reduce() പോലുള്ള ഒരു ടെർമിനൽ മെത്തേഡ് വിളിക്കുന്നതുവരെ യഥാർത്ഥത്തിൽ ഒന്നും സംഭവിക്കുന്നില്ല. ഈ തത്വത്തെ ലേസി ഇവാലുവേഷൻ എന്ന് പറയുന്നു.
സ്ട്രീം ഫ്യൂഷന്റെ മാന്ത്രികത: ഒരേ സമയം ഓരോ എലമെന്റ് പ്രോസസ്സ് ചെയ്യുന്നു
ലേസി ഇവാലുവേഷനെ ഇത്രയധികം കാര്യക്ഷമമാക്കുന്ന ഒരു സംവിധാനമാണ് സ്ട്രീം ഫ്യൂഷൻ. മുഴുവൻ ശേഖരത്തെയും വെവ്വേറെ ഘട്ടങ്ങളായി പ്രോസസ്സ് ചെയ്യുന്നതിന് പകരം, ഓരോ എലമെന്റിനെയും പ്രവർത്തനങ്ങളുടെ മുഴുവൻ ശൃംഖലയിലൂടെയും വ്യക്തിഗതമായി പ്രോസസ്സ് ചെയ്യുന്നു.
അസംബ്ലി ലൈൻ സാമ്യം
ഒരു നിർമ്മാണശാല സങ്കൽപ്പിക്കുക. പരമ്പരാഗത അറേ രീതി ഓരോ ഘട്ടത്തിനും വെവ്വേറെ മുറികൾ ഉള്ളതുപോലെയാണ്:
- റൂം 1 (ഫിൽട്ടറിംഗ്): എല്ലാ അസംസ്കൃത വസ്തുക്കളും (മുഴുവൻ അറേയും) അകത്തേക്ക് കൊണ്ടുവരുന്നു. തൊഴിലാളികൾ മോശം വസ്തുക്കളെ അരിച്ചെടുക്കുന്നു. നല്ലവയെല്ലാം ഒരു വലിയ ബിന്നിൽ (ആദ്യത്തെ ഇടനില അറേ) വയ്ക്കുന്നു.
- റൂം 2 (മാപ്പിംഗ്): നല്ല വസ്തുക്കളുടെ മുഴുവൻ ബിന്നും അടുത്ത മുറിയിലേക്ക് മാറ്റുന്നു. ഇവിടെ, തൊഴിലാളികൾ ഓരോ ഇനത്തിലും മാറ്റങ്ങൾ വരുത്തുന്നു. മാറ്റം വരുത്തിയ ഇനങ്ങൾ മറ്റൊരു വലിയ ബിന്നിൽ (രണ്ടാമത്തെ ഇടനില അറേ) വയ്ക്കുന്നു.
- റൂം 3 (എടുക്കൽ): രണ്ടാമത്തെ ബിൻ അവസാന മുറിയിലേക്ക് മാറ്റുന്നു, അവിടെ ഒരു തൊഴിലാളി മുകളിൽ നിന്ന് ആദ്യത്തെ അഞ്ച് ഇനങ്ങൾ എടുത്ത് ബാക്കിയുള്ളവ ഉപേക്ഷിക്കുന്നു.
ഈ പ്രക്രിയ ഗതാഗതത്തിലും (മെമ്മറി അലോക്കേഷൻ) അധ്വാനത്തിലും (കമ്പ്യൂട്ടേഷൻ) പാഴാണ്.
ഇറ്ററേറ്റർ ഹെൽപ്പറുകളാൽ പ്രവർത്തിക്കുന്ന സ്ട്രീം ഫ്യൂഷൻ ഒരു ആധുനിക അസംബ്ലി ലൈൻ പോലെയാണ്:
- എല്ലാ സ്റ്റേഷനുകളിലൂടെയും ഒരൊറ്റ കൺവെയർ ബെൽറ്റ് ഓടുന്നു.
- ഒരു ഇനം ബെൽറ്റിൽ വയ്ക്കുന്നു. അത് ഫിൽട്ടറിംഗ് സ്റ്റേഷനിലേക്ക് നീങ്ങുന്നു. പരാജയപ്പെട്ടാൽ അത് നീക്കംചെയ്യുന്നു. പാസായാൽ അത് മുന്നോട്ട് പോകുന്നു.
- അത് ഉടനടി മാപ്പിംഗ് സ്റ്റേഷനിലേക്ക് നീങ്ങുന്നു, അവിടെ അത് പരിഷ്കരിക്കപ്പെടുന്നു.
- തുടർന്ന് അത് കൗണ്ടിംഗ് സ്റ്റേഷനിലേക്ക് (ടേക്ക്) നീങ്ങുന്നു. ഒരു സൂപ്പർവൈസർ അത് എണ്ണുന്നു.
- സൂപ്പർവൈസർ അഞ്ച് വിജയകരമായ ഇനങ്ങൾ എണ്ണുന്നതുവരെ ഇത് ഓരോന്നായി തുടരുന്നു. ആ നിമിഷം, സൂപ്പർവൈസർ "നിർത്തൂ!" എന്ന് വിളിച്ചു പറയുന്നു, അതോടെ അസംബ്ലി ലൈൻ മുഴുവനും പ്രവർത്തനം നിർത്തുന്നു.
ഈ മാതൃകയിൽ, ഇടനില ഉൽപ്പന്നങ്ങളുടെ വലിയ ബിന്നുകൾ ഇല്ല, ജോലി പൂർത്തിയാകുന്ന നിമിഷം ലൈൻ നിർത്തുന്നു. ഇറ്ററേറ്റർ ഹെൽപ്പർ സ്ട്രീം ഫ്യൂഷൻ പ്രവർത്തിക്കുന്നത് കൃത്യമായി ഇങ്ങനെയാണ്.
ഓരോ ഘട്ടമായുള്ള വിശകലനം
നമ്മുടെ ഇറ്ററേറ്റർ ഉദാഹരണത്തിന്റെ പ്രവർത്തനം നമുക്ക് പരിശോധിക്കാം: numbers.values().filter(...).map(...).take(5).toArray().
.toArray()വിളിക്കപ്പെടുന്നു. അതിന് ഒരു വാല്യൂ ആവശ്യമാണ്. അത് അതിന്റെ ഉറവിടമായtake(5)ഇറ്ററേറ്ററിനോട് ആദ്യത്തെ ഇനം ആവശ്യപ്പെടുന്നു.take(5)ഇറ്ററേറ്ററിന് എണ്ണാൻ ഒരു ഇനം ആവശ്യമാണ്. അത് അതിന്റെ ഉറവിടമായmapഇറ്ററേറ്ററിനോട് ഒരു ഇനം ആവശ്യപ്പെടുന്നു.mapഇറ്ററേറ്ററിന് മാറ്റം വരുത്താൻ ഒരു ഇനം ആവശ്യമാണ്. അത് അതിന്റെ ഉറവിടമായfilterഇറ്ററേറ്ററിനോട് ഒരു ഇനം ആവശ്യപ്പെടുന്നു.filterഇറ്ററേറ്ററിന് പരിശോധിക്കാൻ ഒരു ഇനം ആവശ്യമാണ്. അത് സോഴ്സ് അറേ ഇറ്ററേറ്ററിൽ നിന്ന് ആദ്യത്തെ വാല്യൂ എടുക്കുന്നു:1.- '1'-ന്റെ യാത്ര: ഫിൽട്ടർ
1 % 2 === 0എന്ന് പരിശോധിക്കുന്നു. ഇത് തെറ്റാണ്. ഫിൽട്ടർ ഇറ്ററേറ്റർ1-നെ ഉപേക്ഷിച്ച് സോഴ്സിൽ നിന്ന് അടുത്ത വാല്യൂ എടുക്കുന്നു:2. - '2'-ന്റെ യാത്ര:
- ഫിൽട്ടർ
2 % 2 === 0എന്ന് പരിശോധിക്കുന്നു. ഇത് ശരിയാണ്. അത്2-നെmapഇറ്ററേറ്ററിലേക്ക് കൈമാറുന്നു. mapഇറ്ററേറ്റർ2സ്വീകരിച്ച്,2 * 2കണക്കുകൂട്ടി, ഫലമായ4-നെtakeഇറ്ററേറ്ററിലേക്ക് കൈമാറുന്നു.takeഇറ്ററേറ്റർ4സ്വീകരിക്കുന്നു. അത് അതിന്റെ ഇന്റേണൽ കൗണ്ടർ കുറയ്ക്കുകയും (5-ൽ നിന്ന് 4-ലേക്ക്) ഫലമായ `4`-നെ `.toArray()` എന്ന ഉപഭോക്താവിന് നൽകുന്നു. ആദ്യത്തെ ഫലം കണ്ടെത്തിക്കഴിഞ്ഞു.
- ഫിൽട്ടർ
toArray()-ക്ക് ഒരു വാല്യൂ ലഭിച്ചു. അത്take(5)-നോട് അടുത്തത് ആവശ്യപ്പെടുന്നു. ഈ പ്രക്രിയ മുഴുവനും ആവർത്തിക്കുന്നു.- ഫിൽട്ടർ
3എടുക്കുന്നു (പരാജയപ്പെടുന്നു), പിന്നെ4(പാസാകുന്നു).4എന്നതിനെ8-ലേക്ക് മാപ്പ് ചെയ്യുന്നു, അത് എടുക്കുന്നു. take(5)അഞ്ച് വാല്യൂകൾ നൽകുന്നതുവരെ ഇത് തുടരുന്നു. അഞ്ചാമത്തെ വാല്യൂ യഥാർത്ഥ സംഖ്യയായ10-ൽ നിന്നായിരിക്കും, അത്20-ലേക്ക് മാപ്പ് ചെയ്യപ്പെടുന്നു.take(5)ഇറ്ററേറ്റർ അതിന്റെ അഞ്ചാമത്തെ വാല്യൂ നൽകിയാലുടൻ, അതിന്റെ ജോലി കഴിഞ്ഞുവെന്ന് അതിന് മനസ്സിലാകും. അടുത്ത തവണ ഒരു വാല്യൂ ആവശ്യപ്പെടുമ്പോൾ, അത് പൂർത്തിയായി എന്ന് സൂചന നൽകും. മുഴുവൻ ശൃംഖലയും നിലയ്ക്കുന്നു.11,12എന്നീ സംഖ്യകളും സോഴ്സ് അറേയിലെ ദശലക്ഷക്കണക്കിന് മറ്റ് സംഖ്യകളും പരിശോധിക്കപ്പെടുന്നതേയില്ല.
ഇതിന്റെ പ്രയോജനങ്ങൾ വളരെ വലുതാണ്: ഇടനില അറേകൾ ഇല്ല, ഏറ്റവും കുറഞ്ഞ മെമ്മറി ഉപയോഗം, കമ്പ്യൂട്ടേഷൻ കഴിയുന്നത്ര നേരത്തെ നിർത്തുന്നു. ഇത് കാര്യക്ഷമതയിലെ ഒരു വലിയ മാറ്റമാണ്.
പ്രായോഗിക ഉപയോഗങ്ങളും പ്രകടന നേട്ടങ്ങളും
ഇറ്ററേറ്റർ ഹെൽപ്പറുകളുടെ ശക്തി ലളിതമായ അറേ മാനിപ്പുലേഷനും അപ്പുറത്തേക്ക് വ്യാപിക്കുന്നു. സങ്കീർണ്ണമായ ഡാറ്റാ പ്രോസസ്സിംഗ് ജോലികൾ കാര്യക്ഷമമായി കൈകാര്യം ചെയ്യുന്നതിനുള്ള പുതിയ സാധ്യതകൾ ഇത് തുറക്കുന്നു.
സാഹചര്യം 1: വലിയ ഡാറ്റാസെറ്റുകളും സ്ട്രീമുകളും പ്രോസസ്സ് ചെയ്യുമ്പോൾ
ഒരു മൾട്ടി-ജിഗാബൈറ്റ് ലോഗ് ഫയലോ നെറ്റ്വർക്ക് സോക്കറ്റിൽ നിന്നുള്ള ഡാറ്റയുടെ ഒരു സ്ട്രീമോ പ്രോസസ്സ് ചെയ്യേണ്ടതുണ്ടെന്ന് സങ്കൽപ്പിക്കുക. ഫയൽ മുഴുവനായി മെമ്മറിയിലെ ഒരു അറേയിലേക്ക് ലോഡ് ചെയ്യുന്നത് പലപ്പോഴും അസാധ്യമാണ്.
ഇറ്ററേറ്ററുകൾ ഉപയോഗിച്ച് (പ്രത്യേകിച്ച് അസിങ്ക് ഇറ്ററേറ്ററുകൾ, അത് പിന്നീട് ചർച്ചചെയ്യാം), നിങ്ങൾക്ക് ഡാറ്റ ഓരോ ഭാഗമായി പ്രോസസ്സ് ചെയ്യാൻ കഴിയും.
// ഒരു വലിയ ഫയലിൽ നിന്ന് വരികൾ നൽകുന്ന ഒരു ജനറേറ്ററിന്റെ സാങ്കൽപ്പിക ഉദാഹരണം
function* readLines(filePath) {
// ഫയൽ മുഴുവനായി ലോഡ് ചെയ്യാതെ വരിവരിയായി വായിക്കുന്നതിനുള്ള കോഡ്
// yield line;
}
const errorCount = readLines('huge_app.log').values()
.map(line => JSON.parse(line))
.filter(logEntry => logEntry.level === 'error')
.take(100) // ആദ്യത്തെ 100 എററുകൾ കണ്ടെത്തുക
.reduce((count) => count + 1, 0);
ഈ ഉദാഹരണത്തിൽ, ഫയലിന്റെ ഒരു വരി മാത്രമേ ഒരേ സമയം മെമ്മറിയിൽ ഉണ്ടാകൂ, അത് പൈപ്പ്ലൈനിലൂടെ കടന്നുപോകുമ്പോൾ. പ്രോഗ്രാമിന് കുറഞ്ഞ മെമ്മറി ഉപയോഗിച്ച് ടെറാബൈറ്റ് ഡാറ്റ പ്രോസസ്സ് ചെയ്യാൻ കഴിയും.
സാഹചര്യം 2: നേരത്തെയുള്ള അവസാനിപ്പിക്കലും ഷോർട്ട്-സർക്യൂട്ടിംഗും
നമ്മൾ ഇത് .take() ഉപയോഗിച്ച് ഇതിനകം കണ്ടു, എന്നാൽ ഇത് .find(), .some(), .every() പോലുള്ള മെത്തേഡുകൾക്കും ബാധകമാണ്. ഒരു വലിയ ഡാറ്റാബേസിൽ നിന്ന് ഒരു അഡ്മിനിസ്ട്രേറ്ററായ ആദ്യത്തെ ഉപയോക്താവിനെ കണ്ടെത്തുന്നത് പരിഗണിക്കുക.
അറേ അടിസ്ഥാനമാക്കിയത് (കാര്യക്ഷമമല്ലാത്തത്):
const firstAdmin = users.filter(u => u.isAdmin)[0];
ഇവിടെ, ആദ്യത്തെ ഉപയോക്താവ് ഒരു അഡ്മിൻ ആണെങ്കിൽ പോലും, .filter() മുഴുവൻ users അറേയിലൂടെയും കടന്നുപോകും.
ഇറ്ററേറ്റർ അടിസ്ഥാനമാക്കിയത് (കാര്യക്ഷമമായത്):
const firstAdmin = users.values().find(u => u.isAdmin);
.find() ഹെൽപ്പർ ഓരോ ഉപയോക്താവിനെയും ഒന്നൊന്നായി പരിശോധിച്ച് ആദ്യത്തെ പൊരുത്തം കണ്ടെത്തിയാലുടൻ മുഴുവൻ പ്രക്രിയയും നിർത്തും.
സാഹചര്യം 3: അനന്തമായ ശ്രേണികളുമായി പ്രവർത്തിക്കുമ്പോൾ
ലേസി ഇവാലുവേഷൻ, അനന്തമായ ഡാറ്റാ ഉറവിടങ്ങളുമായി പ്രവർത്തിക്കുന്നത് സാധ്യമാക്കുന്നു, ഇത് അറകൾ ഉപയോഗിച്ച് അസാധ്യമാണ്. അത്തരം ശ്രേണികൾ സൃഷ്ടിക്കാൻ ജനറേറ്ററുകൾ അനുയോജ്യമാണ്.
function* fibonacci() {
let a = 0, b = 1;
while (true) {
yield a;
[a, b] = [b, a + b];
}
}
// 1000-ത്തിൽ കൂടുതലുള്ള ആദ്യത്തെ 10 ഫിബൊനാച്ചി സംഖ്യകൾ കണ്ടെത്തുക
const result = fibonacci()
.filter(n => n > 1000)
.take(10)
.toArray();
// ഫലം [1597, 2584, 4181, 6765, 10946, 17711, 28657, 46368, 75025, 121393] ആയിരിക്കും
ഈ കോഡ് തികച്ചും പ്രവർത്തിക്കുന്നു. fibonacci() ജനറേറ്ററിന് എക്കാലവും പ്രവർത്തിക്കാൻ കഴിയും, എന്നാൽ പ്രവർത്തനങ്ങൾ ലേസി ആയതിനാലും .take(10) ഒരു സ്റ്റോപ്പ് കണ്ടീഷൻ നൽകുന്നതിനാലും, പ്രോഗ്രാം അഭ്യർത്ഥന നിറവേറ്റാൻ ആവശ്യമായ അത്രയും ഫിബൊനാച്ചി സംഖ്യകൾ മാത്രമേ കണക്കുകൂട്ടുന്നുള്ളൂ.
വിശാലമായ ഇക്കോസിസ്റ്റത്തിലേക്ക് ഒരു നോട്ടം: അസിങ്ക് ഇറ്ററേറ്ററുകൾ
ഈ പ്രൊപ്പോസലിന്റെ ഭംഗി അത് സിൻക്രണസ് ഇറ്ററേറ്ററുകളിൽ മാത്രം ഒതുങ്ങുന്നില്ല എന്നതാണ്. ഇത് AsyncIterator.prototype-ൽ അസിങ്ക് ഇറ്ററേറ്ററുകൾക്ക് വേണ്ടിയുള്ള ഒരു സമാന്തര ഹെൽപ്പർ സെറ്റും നിർവചിക്കുന്നു. അസിൻക്രണസ് ഡാറ്റാ സ്ട്രീമുകൾ സർവ്വസാധാരണമായ ആധുനിക ജാവാസ്ക്രിപ്റ്റിന് ഇതൊരു ഗെയിം-ചേഞ്ചറാണ്.
ഒരു പേജിനേറ്റഡ് എപിഐ പ്രോസസ്സ് ചെയ്യുന്നത്, Node.js-ൽ നിന്ന് ഒരു ഫയൽ സ്ട്രീം വായിക്കുന്നത്, അല്ലെങ്കിൽ ഒരു വെബ്സോക്കറ്റിൽ നിന്നുള്ള ഡാറ്റ കൈകാര്യം ചെയ്യുന്നത് സങ്കൽപ്പിക്കുക. ഇവയെല്ലാം സ്വാഭാവികമായും അസിങ്ക് സ്ട്രീമുകളായി പ്രതിനിധീകരിക്കുന്നു. അസിങ്ക് ഇറ്ററേറ്റർ ഹെൽപ്പറുകൾ ഉപയോഗിച്ച്, നിങ്ങൾക്ക് അതേ ഡിക്ലറേറ്റീവ് .map(), .filter() സിന്റാക്സ് അവയിൽ ഉപയോഗിക്കാം.
// ഒരു പേജിനേറ്റഡ് എപിഐ പ്രോസസ്സ് ചെയ്യുന്നതിന്റെ സാങ്കൽപ്പിക ഉദാഹരണം
async function* fetchAllUsers() {
let url = '/api/users?page=1';
while (url) {
const response = await fetch(url);
const data = await response.json();
for (const user of data.users) {
yield user;
}
url = data.nextPageUrl;
}
}
// ഒരു പ്രത്യേക രാജ്യത്ത് നിന്നുള്ള സജീവമായ ആദ്യ 5 ഉപയോക്താക്കളെ കണ്ടെത്തുക
const activeUsers = await fetchAllUsers()
.filter(user => user.isActive)
.filter(user => user.country === 'DE')
.take(5)
.toArray();
ഇത് ജാവാസ്ക്രിപ്റ്റിലെ ഡാറ്റാ പ്രോസസ്സിംഗിനുള്ള പ്രോഗ്രാമിംഗ് മാതൃകയെ ഏകീകരിക്കുന്നു. നിങ്ങളുടെ ഡാറ്റ ഒരു ലളിതമായ ഇൻ-മെമ്മറി അറേയിലായാലും അല്ലെങ്കിൽ ഒരു വിദൂര സെർവറിൽ നിന്നുള്ള അസിൻക്രണസ് സ്ട്രീമിലായാലും, നിങ്ങൾക്ക് ഒരേ ശക്തവും കാര്യക്ഷമവും വായിക്കാൻ എളുപ്പമുള്ളതുമായ പാറ്റേണുകൾ ഉപയോഗിക്കാം.
എങ്ങനെ തുടങ്ങാം, ഇപ്പോഴത്തെ അവസ്ഥ
2024-ന്റെ തുടക്കത്തിൽ, ഇറ്ററേറ്റർ ഹെൽപ്പേഴ്സ് പ്രൊപ്പോസൽ TC39 പ്രക്രിയയുടെ സ്റ്റേജ് 3-ലാണ്. ഇതിനർത്ഥം ഡിസൈൻ പൂർത്തിയായി, ഭാവിയിലെ ഒരു എക്മാസ്ക്രിപ്റ്റ് സ്റ്റാൻഡേർഡിൽ ഇത് ഉൾപ്പെടുത്തുമെന്ന് കമ്മിറ്റി പ്രതീക്ഷിക്കുന്നു. ഇത് ഇപ്പോൾ പ്രധാന ജാവാസ്ക്രിപ്റ്റ് എഞ്ചിനുകളിൽ നടപ്പിലാക്കുന്നതിനും ആ നടപ്പാക്കലുകളിൽ നിന്നുള്ള ഫീഡ്ബെക്കിനുമായി കാത്തിരിക്കുകയാണ്.
ഇന്ന് ഇറ്ററേറ്റർ ഹെൽപ്പറുകൾ എങ്ങനെ ഉപയോഗിക്കാം
- ബ്രൗസർ, Node.js റൺടൈമുകൾ: പ്രധാന ബ്രൗസറുകളുടെ (Chrome/V8 പോലുള്ളവ) ഏറ്റവും പുതിയ പതിപ്പുകളും Node.js-ഉം ഈ ഫീച്ചറുകൾ നടപ്പിലാക്കാൻ തുടങ്ങിയിരിക്കുന്നു. അവ നേറ്റീവ് ആയി ഉപയോഗിക്കാൻ ഒരു പ്രത്യേക ഫ്ലാഗ് പ്രവർത്തനക്ഷമമാക്കുകയോ ഏറ്റവും പുതിയ പതിപ്പ് ഉപയോഗിക്കുകയോ ചെയ്യേണ്ടി വന്നേക്കാം. എപ്പോഴും ഏറ്റവും പുതിയ കോംപാറ്റിബിലിറ്റി പട്ടികകൾ പരിശോധിക്കുക (ഉദാഹരണത്തിന്, MDN അല്ലെങ്കിൽ caniuse.com-ൽ).
- പോളിഫില്ലുകൾ: പഴയ റൺടൈമുകളെ പിന്തുണയ്ക്കേണ്ട പ്രൊഡക്ഷൻ എൻവയോൺമെന്റുകൾക്കായി, നിങ്ങൾക്ക് ഒരു പോളിഫിൽ ഉപയോഗിക്കാം.
core-jsലൈബ്രറിയിലൂടെയാണ് ഏറ്റവും സാധാരണമായ മാർഗ്ഗം, ഇത് പലപ്പോഴും Babel പോലുള്ള ട്രാൻസ്പൈലറുകൾ ഉൾപ്പെടുത്തുന്നു. Babel-ഉംcore-js-ഉം കോൺഫിഗർ ചെയ്യുന്നതിലൂടെ, നിങ്ങൾക്ക് ഇറ്ററേറ്റർ ഹെൽപ്പറുകൾ ഉപയോഗിച്ച് കോഡ് എഴുതാനും അത് പഴയ എൻവയോൺമെന്റുകളിൽ പ്രവർത്തിക്കുന്ന തത്തുല്യമായ കോഡായി മാറ്റാനും കഴിയും.
ഉപസംഹാരം: ജാവസ്ക്രിപ്റ്റിലെ കാര്യക്ഷമമായ ഡാറ്റാ പ്രോസസ്സിംഗിന്റെ ഭാവി
ഇറ്ററേറ്റർ ഹെൽപ്പേഴ്സ് പ്രൊപ്പോസൽ ഒരു കൂട്ടം പുതിയ മെത്തേഡുകൾ മാത്രമല്ല; ഇത് ജാവാസ്ക്രിപ്റ്റിൽ കൂടുതൽ കാര്യക്ഷമവും സ്കേലബിളും വ്യക്തവുമായ ഡാറ്റാ പ്രോസസ്സിംഗിലേക്കുള്ള ഒരു അടിസ്ഥാനപരമായ മാറ്റത്തെ പ്രതിനിധീകരിക്കുന്നു. ലേസി ഇവാലുവേഷനും സ്ട്രീം ഫ്യൂഷനും സ്വീകരിക്കുന്നതിലൂടെ, വലിയ ഡാറ്റാസെറ്റുകളിൽ അറേ മെത്തേഡുകൾ ഒരുമിച്ച് ഉപയോഗിക്കുന്നതുമായി ബന്ധപ്പെട്ട ദീർഘകാല പ്രകടന പ്രശ്നങ്ങൾ ഇത് പരിഹരിക്കുന്നു.
ഓരോ ഡെവലപ്പർക്കുമുള്ള പ്രധാന പാഠങ്ങൾ ഇവയാണ്:
- സ്ഥിരമായി മികച്ച പ്രകടനം: ഇറ്ററേറ്റർ മെത്തേഡുകൾ ഒരുമിച്ച് ഉപയോഗിക്കുന്നത് ഇടനില ശേഖരങ്ങളെ ഒഴിവാക്കുന്നു, ഇത് മെമ്മറി ഉപയോഗവും ഗാർബേജ് കളക്ടർ ലോഡും ഗണ്യമായി കുറയ്ക്കുന്നു.
- ലേസിനസ്സിലൂടെ മെച്ചപ്പെട്ട നിയന്ത്രണം: ആവശ്യമുള്ളപ്പോൾ മാത്രം കണക്കുകൂട്ടലുകൾ നടത്തുന്നു, ഇത് നേരത്തെയുള്ള അവസാനിപ്പിക്കലും അനന്തമായ ഡാറ്റാ ഉറവിടങ്ങളുടെ ലളിതമായ കൈകാര്യം ചെയ്യലും സാധ്യമാക്കുന്നു.
- ഒരു ഏകീകൃത മാതൃക: ഒരേ ശക്തമായ പാറ്റേണുകൾ സിൻക്രണസ്, അസിൻക്രണസ് ഡാറ്റകൾക്ക് ഒരുപോലെ ബാധകമാണ്, ഇത് കോഡ് ലളിതമാക്കുകയും സങ്കീർണ്ണമായ ഡാറ്റാ ഫ്ലോകളെക്കുറിച്ച് ചിന്തിക്കുന്നത് എളുപ്പമാക്കുകയും ചെയ്യുന്നു.
ഈ ഫീച്ചർ ജാവാസ്ക്രിപ്റ്റ് ഭാഷയുടെ ഒരു സാധാരണ ഭാഗമായി മാറുമ്പോൾ, ഇത് പ്രകടനത്തിന്റെ പുതിയ തലങ്ങൾ തുറക്കുകയും കൂടുതൽ കരുത്തുറ്റതും സ്കേലബിളുമായ ആപ്ലിക്കേഷനുകൾ നിർമ്മിക്കാൻ ഡെവലപ്പർമാരെ ശാക്തീകരിക്കുകയും ചെയ്യും. സ്ട്രീമുകളിൽ ചിന്തിച്ചു തുടങ്ങാനും നിങ്ങളുടെ കരിയറിലെ ഏറ്റവും കാര്യക്ഷമമായ ഡാറ്റാ-പ്രോസസ്സിംഗ് കോഡ് എഴുതാൻ തയ്യാറാകാനുമുള്ള സമയമാണിത്.