நினைவக-திறனுள்ள Observer pattern-ஐ உருவாக்க JavaScript-ன் WeakRef மற்றும் FinalizationRegistry பற்றிய ஆழமான ஆய்வு. பெரிய அளவிலான பயன்பாடுகளில் நினைவக கசிவுகளைத் தடுக்க கற்றுக்கொள்ளுங்கள்.
JavaScript WeakRef Observer Pattern: நினைவக-உணர்திறன் நிகழ்வு அமைப்புகளை உருவாக்குதல்
நவீன வலை மேம்பாட்டின் உலகில், ஒற்றை பக்க பயன்பாடுகள் (SPAs) மாறும் மற்றும் பதிலளிக்கக்கூடிய பயனர் அனுபவங்களை உருவாக்குவதற்கான தரநிலையாகிவிட்டன. இந்த பயன்பாடுகள் பெரும்பாலும் நீண்ட காலத்திற்கு இயங்குகின்றன, சிக்கலான நிலையை நிர்வகிக்கின்றன மற்றும் எண்ணற்ற பயனர் தொடர்புகளை கையாள்கின்றன. இருப்பினும், இந்த நீண்ட ஆயுள் ஒரு மறைக்கப்பட்ட விலையுடன் வருகிறது: நினைவக கசிவுகளின் ஆபத்து அதிகரித்துள்ளது. ஒரு நினைவக கசிவு, அங்கு ஒரு பயன்பாடு இனி தேவைப்படாத நினைவகத்தை வைத்திருக்கிறது, காலப்போக்கில் செயல்திறனைக் குறைக்கலாம், மெதுவாக இயங்குதல், உலாவி செயலிழப்புகள் மற்றும் மோசமான பயனர் அனுபவத்திற்கு வழிவகுக்கும். இந்த கசிவுகளின் மிகவும் பொதுவான ஆதாரங்களில் ஒன்று அடிப்படை வடிவமைப்பு வடிவத்தில் உள்ளது: Observer pattern.
Observer pattern என்பது நிகழ்வு-இயக்கப்படும் கட்டமைப்பின் ஒரு மூலக்கல்லாகும், இது பொருள்கள் (observers) ஒரு மையப் பொருளிலிருந்து (subject) புதுப்பிப்புகளைப் பெறவும் பெறவும் அனுமதிக்கிறது. இது நேர்த்தியானது, எளிமையானது மற்றும் நம்பமுடியாத அளவிற்கு பயனுள்ளது. ஆனால் அதன் உன்னதமான செயல்படுத்தலில் ஒரு முக்கியமான குறைபாடு உள்ளது: subject அதன் observers-க்கு வலுவான குறிப்புகளை வைத்திருக்கிறது. ஒரு observer பயன்பாட்டின் மீதமுள்ள பயன்பாட்டால் இனி தேவைப்படாவிட்டால், ஆனால் டெவலப்பர் அதை subject-லிருந்து வெளிப்படையாக சந்தா நீக்க மறந்தால், அது ஒருபோதும் குப்பை சேகரிக்கப்படாது. இது நினைவகத்தில் சிக்கி, உங்கள் பயன்பாட்டின் செயல்திறனை அச்சுறுத்தும் ஒரு பேயாக இருக்கும்.
இது நவீன JavaScript, அதன் ECMAScript 2021 (ES12) அம்சங்களுடன், ஒரு சக்திவாய்ந்த தீர்வை வழங்குகிறது. WeakRef மற்றும் FinalizationRegistry-ஐப் பயன்படுத்துவதன் மூலம், நாம் தானாகவே சுத்தம் செய்யும் ஒரு நினைவக-உணர்திறன் Observer pattern-ஐ உருவாக்கலாம், இது இந்த பொதுவான கசிவுகளைத் தடுக்கிறது. இந்த கட்டுரை இந்த மேம்பட்ட நுட்பத்தைப் பற்றிய ஒரு ஆழமான ஆய்வு ஆகும். நாம் பிரச்சனையைப் பற்றி ஆராய்வோம், கருவிகளைப் புரிந்துகொள்வோம், புதிதாக ஒரு வலுவான செயல்படுத்தலை உருவாக்குவோம், மேலும் உங்கள் உலகளாவிய பயன்பாடுகளில் இந்த சக்திவாய்ந்த pattern எப்போது, எங்கு பயன்படுத்தப்பட வேண்டும் என்பதை விவாதிப்போம்.
முக்கிய பிரச்சனையைப் புரிந்துகொள்ளுதல்: உன்னதமான Observer Pattern மற்றும் அதன் நினைவக கால் தடம்
நாம் தீர்வைப் பாராட்ட முடியும் முன், நாம் பிரச்சனையை முழுமையாகப் புரிந்துகொள்ள வேண்டும். Observer pattern, Publisher-Subscriber pattern என்றும் அழைக்கப்படுகிறது, இது கூறுகளைப் பிரிக்க வடிவமைக்கப்பட்டுள்ளது. ஒரு Subject (அல்லது Publisher) அதன் சார்ந்திருப்பவர்களின் பட்டியலை, Observers (அல்லது Subscribers) என்று அழைக்கிறது. Subject-ன் நிலை மாறும்போது, அது தானாகவே அதன் அனைத்து Observers-க்கும் தெரிவிக்கிறது, பொதுவாக அவற்றின் மீது ஒரு குறிப்பிட்ட முறையை அழைப்பதன் மூலம், update() போன்றது.
JavaScript-ல் ஒரு எளிய, உன்னதமான செயல்படுத்தலைப் பார்ப்போம்.
ஒரு எளிய Subject செயல்படுத்தல்
இங்கே ஒரு அடிப்படை Subject வகுப்பு உள்ளது. இது observers-ஐ சந்தா, சந்தா நீக்குதல் மற்றும் அறிவித்தல் முறைகளைக் கொண்டுள்ளது.
class ClassicSubject {
constructor() {
this.observers = [];
}
subscribe(observer) {
this.observers.push(observer);
console.log(`${observer.name} has subscribed.`);
}
unsubscribe(observer) {
this.observers = this.observers.filter(obs => obs !== observer);
console.log(`${observer.name} has unsubscribed.`);
}
notify(data) {
console.log('Notifying observers...');
this.observers.forEach(observer => observer.update(data));
}
}
Subject-க்கு சந்தா செலுத்தக்கூடிய ஒரு எளிய Observer வகுப்பு இங்கே உள்ளது.
class Observer {
constructor(name) {
this.name = name;
}
update(data) {
console.log(`${this.name} received data: ${data}`);
}
}
மறைக்கப்பட்ட ஆபத்து: நீடிக்கும் குறிப்புகள்
நமது observers-ன் ஆயுட்காலத்தை நாம் கவனமாக நிர்வகிக்கும் வரை இந்த செயல்படுத்தல் சரியாக வேலை செய்யும். நாம் செய்யாதபோது பிரச்சனை எழுகிறது. ஒரு பெரிய பயன்பாட்டில் ஒரு பொதுவான காட்சியை கற்பனை செய்யுங்கள்: நீண்ட காலம் நீடிக்கும் உலகளாவிய தரவு சேமிப்பு (Subject) மற்றும் அந்த தரவுகளில் சிலவற்றைக் காண்பிக்கும் தற்காலிக UI கூறு (Observer).
இந்த சூழ்நிலையை உருவகப்படுத்துவோம்:
const dataStore = new ClassicSubject();
function manageUIComponent() {
let chartComponent = new Observer('ChartComponent');
dataStore.subscribe(chartComponent);
// கூறு அதன் வேலையைச் செய்கிறது...
// இப்போது, பயனர் வெளியேறுகிறார், மேலும் கூறு இனி தேவைப்படாது.
// ஒரு டெவலப்பர் தூய்மைப்படுத்தும் குறியீட்டைச் சேர்க்க மறக்கலாம்:
// dataStore.unsubscribe(chartComponent);
chartComponent = null; // நாம் கூறுக்கான நமது குறிப்பை வெளியிடுகிறோம்.
}
manageUIComponent();
// பயன்பாட்டின் ஆயுட்காலத்தில் பின்னர்...
dataStore.notify('New data available!');
`manageUIComponent` செயல்பாட்டில், நாம் ஒரு `chartComponent`-ஐ உருவாக்கி அதை நமது `dataStore`-க்கு சந்தா செலுத்துகிறோம். பின்னர், `chartComponent`-ஐ `null` என அமைக்கிறோம், நாம் அதை முடித்துவிட்டோம் என்பதைக் குறிக்கிறது. இந்த பொருளூக்கு இனி குறிப்புகள் இல்லை என்பதை JavaScript குப்பை சேகரிப்பான் (GC) பார்க்கும் என்றும் அதன் நினைவகத்தை மீட்டெடுக்கும் என்றும் நாம் எதிர்பார்க்கிறோம்.
ஆனால் இன்னும் ஒரு குறிப்பு உள்ளது! `dataStore.observers` வரிசை `chartComponent` பொருளுக்கு ஒரு நேரடி, வலுவான குறிப்பை இன்னும் வைத்திருக்கிறது. இந்த ஒற்றை நீடித்த குறிப்பு காரணமாக, குப்பை சேகரிப்பான் நினைவகத்தை மீட்டெடுக்க முடியாது. `chartComponent` பொருள், மற்றும் அது வைத்திருக்கும் எந்த வளங்களும், `dataStore`-ன் முழு ஆயுட்காலத்திற்கும் நினைவகத்தில் இருக்கும். இது மீண்டும் மீண்டும் நடந்தால்—எடுத்துக்காட்டாக, பயனர் ஒரு மாதிரி சாளரத்தைத் திறந்து மூடும் ஒவ்வொரு முறையும்—பயன்பாட்டின் நினைவக பயன்பாடு காலவரையின்றி வளரும். இது ஒரு உன்னதமான நினைவக கசிவு.
ஒரு புதிய நம்பிக்கை: WeakRef மற்றும் FinalizationRegistry-ஐ அறிமுகப்படுத்துதல்
ECMAScript 2021 இந்த வகையான நினைவக மேலாண்மை சவால்களை கையாள வடிவமைக்கப்பட்ட இரண்டு புதிய அம்சங்களை அறிமுகப்படுத்தியது: `WeakRef` மற்றும் `FinalizationRegistry`. அவை மேம்பட்ட கருவிகள் மற்றும் கவனத்துடன் பயன்படுத்தப்பட வேண்டும், ஆனால் நமது Observer pattern சிக்கலுக்கு, அவை சரியான தீர்வாகும்.
WeakRef என்றால் என்ன?
ஒரு `WeakRef` பொருள் அதன் இலக்கு என்று அழைக்கப்படும் மற்றொரு பொருளுக்கு ஒரு பலவீனமான குறிப்பை வைத்திருக்கிறது. ஒரு பலவீனமான குறிப்புக்கும் சாதாரண (வலுவான) குறிப்புக்கும் இடையிலான முக்கிய வேறுபாடு இதுதான்: ஒரு பலவீனமான குறிப்பு அதன் இலக்கு பொருளை குப்பை சேகரிக்கப்படுவதைத் தடுக்காது.
ஒரு பொருளுக்கான ஒரே குறிப்புகள் பலவீனமான குறிப்புகளாக இருந்தால், JavaScript இயந்திரம் பொருளை அழித்து அதன் நினைவகத்தை மீட்டெடுக்க சுதந்திரமாக உள்ளது. இதுதான் நமது Observer சிக்கலைத் தீர்க்க நமக்குத் தேவையானது.
ஒரு `WeakRef`-ஐப் பயன்படுத்த, நீங்கள் அதன் ஒரு நிகழ்வை உருவாக்கி, இலக்கு பொருளை constructor-க்கு அனுப்பவும். பின்னர் இலக்கு பொருளை அணுக, `deref()` முறையைப் பயன்படுத்தவும்.
let targetObject = { id: 42 };
const weakRefToObject = new WeakRef(targetObject);
// பொருளை அணுக:
const retrievedObject = weakRefToObject.deref();
if (retrievedObject) {
console.log(`Object is still alive: ${retrievedObject.id}`); // வெளியீடு: Object is still alive: 42
} else {
console.log('Object has been garbage collected.');
}
`deref()` `undefined`-ஐ வழங்கக்கூடும் என்பது முக்கியமான பகுதி. `targetObject`-க்கு வலுவான குறிப்புகள் எதுவும் இல்லாததால் `targetObject` குப்பை சேகரிக்கப்பட்டிருந்தால் இது நிகழ்கிறது. இந்த நடத்தை நமது நினைவக-உணர்திறன் Observer pattern-ன் அடித்தளமாகும்.
FinalizationRegistry என்றால் என்ன?
WeakRef ஒரு பொருளை சேகரிக்க அனுமதித்தாலும், அது எப்போது சேகரிக்கப்பட்டது என்பதை அறிய ஒரு சுத்தமான வழியை நமக்கு வழங்காது. நாம் `deref()`-ஐ அவ்வப்போது சரிபார்த்து `undefined` முடிவுகளை நமது observer பட்டியலில் இருந்து அகற்றலாம், ஆனால் அது திறமையற்றது. இங்குதான் `FinalizationRegistry` வருகிறது.
ஒரு `FinalizationRegistry` நீங்கள் பதிவுசெய்த பொருள் குப்பை சேகரிக்கப்பட்ட பிறகு அழைக்கப்படும் ஒரு தூய்மைப்படுத்தும் செயல்பாட்டைப் பதிவு செய்ய உங்களை அனுமதிக்கிறது. இது ஒரு போஸ்ட்-மார்ட்டம் தூய்மைக்கான ஒரு வழிமுறை.
அது எப்படி வேலை செய்கிறது:
- நீங்கள் ஒரு தூய்மைப்படுத்தும் callback உடன் ஒரு registry-ஐ உருவாக்குகிறீர்கள்.
- நீங்கள் registry உடன் ஒரு பொருளை `register()` செய்கிறீர்கள். நீங்கள் ஒரு `heldValue`-ஐயும் வழங்கலாம், இது பொருள் சேகரிக்கப்படும் போது உங்கள் callback-க்கு அனுப்பப்படும் தரவுகளின் ஒரு பகுதியாகும். இந்த `heldValue` பொருளுக்கான நேரடி குறிப்பு அல்லாமல் இருக்க வேண்டும், ஏனெனில் அது நோக்கத்தை அழித்துவிடும்!
// 1. ஒரு தூய்மைப்படுத்தும் callback உடன் registry-ஐ உருவாக்கவும்
const registry = new FinalizationRegistry(heldValue => {
console.log(`An object has been garbage collected. Cleanup token: ${heldValue}`);
});
(function() {
let objectToTrack = { name: 'Temporary Data' };
let cleanupToken = 'temp-data-123';
// 2. பொருளை பதிவு செய்து, தூய்மைப்படுத்துதலுக்கான ஒரு token-ஐ வழங்கவும்
registry.register(objectToTrack, cleanupToken);
// objectToTrack இங்கே scope-க்கு வெளியே செல்கிறது
})();
// எதிர்காலத்தில் ஒரு கட்டத்தில், GC இயங்கிய பிறகு, console பதிவு செய்யும்:
// "An object has been garbage collected. Cleanup token: temp-data-123"
முக்கிய எச்சரிக்கைகள் மற்றும் சிறந்த நடைமுறைகள்
நாம் செயல்படுத்தலில் ஈடுபடுவதற்கு முன், இந்த கருவிகளின் தன்மையைப் புரிந்துகொள்வது மிக முக்கியம். குப்பை சேகரிப்பானின் நடத்தை மிகவும் செயலாக்கத்தைச் சார்ந்தது மற்றும் நிர்ணயிக்கப்படாதது. இதன் பொருள்:
- ஒரு பொருள் சேகரிக்கப்படும் போது நீங்கள் கணிக்க முடியாது. அது அடைய முடியாததாக மாறிய பிறகு சில வினாடிகள், நிமிடங்கள் அல்லது இன்னும் நீண்ட நேரம் ஆகலாம்.
- `FinalizationRegistry` callbacks சரியான நேரத்தில் அல்லது கணிக்கக்கூடிய வகையில் இயங்கும் என்று நீங்கள் நம்ப முடியாது. அவை தூய்மைப்படுத்துதலுக்கானவை, முக்கியமான பயன்பாட்டு தர்க்கத்திற்கு அல்ல.
- `WeakRef` மற்றும் `FinalizationRegistry`-ஐ அதிகமாகப் பயன்படுத்துவது குறியீட்டைப் புரிந்துகொள்வதை கடினமாக்கும். பொருளின் ஆயுட்காலங்கள் தெளிவாகவும் நிர்வகிக்கக்கூடியதாகவும் இருந்தால், எப்போதும் எளிமையான தீர்வுகளை (வெளிப்படையான `unsubscribe` அழைப்புகள் போன்ற) விரும்பவும்.
இந்த அம்சங்கள் ஒரு பொருளின் (observer) ஆயுட்காலம் மற்ற பொருளிடமிருந்து (subject) உண்மையாக சுயாதீனமாகவும் தெரியாமலும் இருக்கும் சூழ்நிலைகளுக்கு மிகவும் பொருத்தமானவை.
`WeakRefObserver` Pattern-ஐ உருவாக்குதல்: ஒரு படி-படி-படியாக செயல்படுத்தல்
இப்போது, நினைவக-பாதுகாப்பான `WeakRefSubject` வகுப்பை உருவாக்க `WeakRef` மற்றும் `FinalizationRegistry`-ஐ இணைப்போம்.
படி 1: `WeakRefSubject` வகுப்பு கட்டமைப்பு
நமது புதிய வகுப்பு observers-ன் `WeakRef`-களை நேரடியாக குறிப்புகளுக்கு பதிலாக சேமிக்கும். மேலும், observers பட்டியலின் தானியங்கி தூய்மைப்படுத்துதலை கையாள ஒரு `FinalizationRegistry`-ஐ கொண்டிருக்கும்.
class WeakRefSubject {
constructor() {
this.observers = new Set(); // எளிதான நீக்கத்திற்காக ஒரு Set-ஐப் பயன்படுத்துதல்
// இறுதிப்படுத்தும் callback. இது பதிவின் போது நாம் வழங்கும் held value-ஐப் பெறுகிறது.
// நமது விஷயத்தில், held value என்பது WeakRef instance ஆகும்.
this.cleanupRegistry = new FinalizationRegistry(weakRefObserver => {
console.log('Finalizer: An observer has been garbage collected. Cleaning up...');
this.observers.delete(weakRefObserver);
});
}
}
நமது observers பட்டியலுக்கு `Array`-க்கு பதிலாக `Set`-ஐப் பயன்படுத்துகிறோம். ஒரு `Set`-லிருந்து ஒரு உருப்படியை நீக்குவது `Array`-ஐ வடிகட்டுவதை விட மிகவும் திறமையானது (O(1) சராசரி நேர சிக்கல்தன்மை), இது நமது தூய்மைப்படுத்தும் தர்க்கத்தில் பயனுள்ளதாக இருக்கும்.
படி 2: `subscribe` முறை
`subscribe` முறைதான் மாயாஜாலம் தொடங்கும் இடம். ஒரு observer சந்தா செலுத்தும்போது, நாம்:
- observer-ஐ சுட்டிக்காட்டும் ஒரு `WeakRef`-ஐ உருவாக்குவோம்.
- இந்த `WeakRef`-ஐ நமது `observers` set-க்கு சேர்ப்போம்.
- `FinalizationRegistry`-உடன் அசல் observer பொருளை பதிவு செய்வோம், புதிய `WeakRef`-ஐ `heldValue`-ஆகப் பயன்படுத்துவோம்.
// WeakRefSubject வகுப்பிற்குள்...
subscribe(observer) {
// இந்த குறிப்புடன் ஒரு observer ஏற்கனவே உள்ளதா என சரிபார்க்கவும்
for (const ref of this.observers) {
if (ref.deref() === observer) {
console.warn('Observer already subscribed.');
return;
}
}
const weakRefObserver = new WeakRef(observer);
this.observers.add(weakRefObserver);
// அசல் observer பொருளை பதிவு செய்யவும். அது சேகரிக்கப்படும்போது,
// weakRefObserver argument ஆக இறுதிப்படுத்தும் callback அழைக்கப்படும்.
this.cleanupRegistry.register(observer, weakRefObserver);
console.log('An observer has subscribed.');
}
இந்த அமைப்பு ஒரு புத்திசாலித்தனமான சுழற்சியை உருவாக்குகிறது: subject observer-க்கு ஒரு பலவீனமான குறிப்பை வைத்திருக்கிறது. registry observer-க்கு ஒரு வலுவான குறிப்பை வைத்திருக்கிறது (உள்ளுக்குள்) அது குப்பை சேகரிக்கப்படும் வரை. சேகரிக்கப்பட்டவுடன், registry-ன் callback அழைக்கப்படும், அதை நாம் நமது `observers` set-ஐ தூய்மைப்படுத்த பயன்படுத்தலாம்.
படி 3: `unsubscribe` முறை
தானியங்கி தூய்மைப்படுத்துதல் இருந்தாலும், நாம் இன்னும் ஒரு கையேடு `unsubscribe` முறையை வழங்க வேண்டும், அங்கு தீர்மானிக்கக்கூடிய நீக்கம் தேவைப்படுகிறது. இந்த முறை நமது set-ல் உள்ள சரியான `WeakRef`-ஐ ஒவ்வொரு ஒன்றையும் dereferencing செய்வதன் மூலமும், நாம் அகற்ற விரும்பும் observer-உடன் ஒப்பிடுவதன் மூலமும் கண்டறிய வேண்டும்.
// WeakRefSubject வகுப்பிற்குள்...
unsubscribe(observer) {
let refToRemove = null;
for (const weakRef of this.observers) {
if (weakRef.deref() === observer) {
refToRemove = weakRef;
break;
}
}
if (refToRemove) {
this.observers.delete(refToRemove);
// முக்கியம்: நாம் இறுதிப்படுத்தும் பதிவில் இருந்தும் நீக்க வேண்டும்
// callback பின்னர் தேவையற்ற முறையில் இயங்குவதைத் தடுக்க.
this.cleanupRegistry.unregister(observer);
console.log('An observer has unsubscribed manually.');
}
}
படி 4: `notify` முறை
`notify` முறை `WeakRef`-களின் நமது set-ஐ iterate செய்கிறது. ஒவ்வொன்றிற்கும், அது உண்மையான observer பொருளைப் பெற அதை `deref()` செய்ய முயற்சிக்கிறது. `deref()` வெற்றி பெற்றால், observer இன்னும் உயிருடன் உள்ளது என்று அர்த்தம், மேலும் நாம் அதன் `update` முறையை அழைக்கலாம். அது `undefined`-ஐ வழங்கினால், observer சேகரிக்கப்பட்டுள்ளது, மேலும் நாம் அதை புறக்கணிக்கலாம். `FinalizationRegistry` இறுதியில் அதன் `WeakRef`-ஐ set-லிருந்து அகற்றும்.
// WeakRefSubject வகுப்பிற்குள்...
notify(data) {
console.log('Notifying observers...');
for (const weakRefObserver of this.observers) {
const observer = weakRefObserver.deref();
if (observer) {
// observer இன்னும் உயிருடன் உள்ளது
observer.update(data);
} else {
// observer குப்பை சேகரிக்கப்பட்டுள்ளது.
// FinalizationRegistry இந்த weakRef-ஐ set-லிருந்து அகற்றும்.
console.log('Found a dead observer reference during notification.');
}
}
}
அனைத்தையும் ஒன்றாக இணைத்தல்: ஒரு நடைமுறை உதாரணம்
இப்போது நமது புதிய `WeakRefSubject`-ஐப் பயன்படுத்தி நமது UI கூறு சூழ்நிலையை மீண்டும் பார்ப்போம். எளிமைக்காக நாம் அதே `Observer` வகுப்பைப் பயன்படுத்துவோம்.
// அதே எளிய Observer வகுப்பு
class Observer {
constructor(name) {
this.name = name;
}
update(data) {
console.log(`${this.name} received data: ${data}`);
}
}
இப்போது ஒரு உலகளாவிய தரவு சேவை மற்றும் ஒரு தற்காலிக UI விட்ஜெட்டை உருவகப்படுத்துவோம்.
const globalDataService = new WeakRefSubject();
function createAndDestroyWidget() {
console.log('--- Creating and subscribing new widget ---');
let chartWidget = new Observer('RealTimeChartWidget');
globalDataService.subscribe(chartWidget);
// விட்ஜெட் இப்போது செயலில் உள்ளது மற்றும் அறிவிப்புகளைப் பெறும்
globalDataService.notify({ price: 100 });
console.log('--- Destroying widget (releasing our reference) ---');
// நாம் விட்ஜெட்டுடன் செய்துவிட்டோம். நமது குறிப்பை null என அமைக்கிறோம்.
// நாம் unsubscribe() அழைக்க வேண்டியதில்லை.
chartWidget = null;
}
createAndDestroyWidget();
console.log('--- After widget destruction, before garbage collection ---');
globalDataService.notify({ price: 105 });
`createAndDestroyWidget()`-ஐ இயக்கிய பிறகு, `chartWidget` பொருள் இப்போது நமது `globalDataService`-க்குள் `WeakRef`-ஆல் மட்டுமே குறிக்கப்படுகிறது. இது ஒரு பலவீனமான குறிப்பு என்பதால், பொருள் இப்போது குப்பை சேகரிப்பிற்கு தகுதியானது.
குப்பை சேகரிப்பான் இறுதியில் இயங்கும்போது (நாம் கணிக்க முடியாது), இரண்டு விஷயங்கள் நடக்கும்:
- `chartWidget` பொருள் நினைவகத்திலிருந்து அகற்றப்படும்.
- நமது `FinalizationRegistry`-ன் callback தூண்டப்படும், இது பின்னர் `globalDataService.observers` set-லிருந்து இறந்த `WeakRef`-ஐ அகற்றும்.
குப்பை சேகரிப்பான் இயங்கிய பிறகு நாம் மீண்டும் `notify`-ஐ அழைத்தால், `deref()` அழைப்பு `undefined`-ஐ வழங்கும், இறந்த observer புறக்கணிக்கப்படும், மேலும் பயன்பாடு எந்த நினைவக கசிவுகளும் இல்லாமல் திறமையாக தொடர்ந்து இயங்கும். நாம் observer-ன் ஆயுட்காலத்தை subject-லிருந்து வெற்றிகரமாகப் பிரித்துள்ளோம்.
எப்போது பயன்படுத்த வேண்டும் (மற்றும் எப்போது தவிர்க்க வேண்டும்) `WeakRefObserver` Pattern
இந்த pattern சக்தி வாய்ந்தது, ஆனால் இது ஒரு வெள்ளி குண்டு அல்ல. இது சிக்கலை அறிமுகப்படுத்துகிறது மற்றும் நிர்ணயிக்கப்படாத நடத்தையை நம்பியுள்ளது. இது வேலைக்கு சரியான கருவி எப்போது என்பதை அறிவது முக்கியம்.
சிறந்த பயன்பாட்டு வழக்குகள்
- நீண்ட காலம் நீடிக்கும் Subjects மற்றும் குறுகிய காலம் நீடிக்கும் Observers: இது பொதுவான பயன்பாட்டு வழக்கு. பயன்பாட்டின் முழு ஆயுட்காலத்திற்கும் இருக்கும் ஒரு உலகளாவிய சேவை, தரவு சேமிப்பு அல்லது cache (subject), அதே நேரத்தில் எண்ணற்ற UI கூறுகள், தற்காலிக பணியாளர்கள் அல்லது செருகுநிரல்கள் (observers) அடிக்கடி உருவாக்கப்பட்டு அழிக்கப்படுகின்றன.
- Cache வழிமுறைகள்: ஒரு சிக்கலான பொருளை ஒரு கணக்கிடப்பட்ட முடிவுடன் மேப் செய்யும் cache-ஐ கற்பனை செய்யுங்கள். நீங்கள் முக்கிய பொருளுக்கு `WeakRef`-ஐப் பயன்படுத்தலாம். மற்ற பயன்பாட்டிலிருந்து அசல் பொருள் குப்பை சேகரிக்கப்பட்டால், `FinalizationRegistry` தானாகவே உங்கள் cache-ல் உள்ள தொடர்புடைய entry-ஐ தூய்மைப்படுத்தலாம், நினைவக வீக்கத்தைத் தடுக்கலாம்.
- Plugin மற்றும் Extension Architecture-கள்: நிகழ்வுகளுக்கு சந்தா செலுத்த மூன்றாம் தரப்பு தொகுதிக்கூறுகளை அனுமதிக்கும் ஒரு முக்கிய அமைப்பை நீங்கள் உருவாக்குகிறீர்கள் என்றால், `WeakRefObserver`-ஐப் பயன்படுத்துவது ஒரு நிலைத்தன்மையை சேர்க்கிறது. இது சந்தா நீக்க மறக்கும் ஒரு மோசமான செருகுநிரல் உங்கள் முக்கிய பயன்பாட்டில் நினைவக கசிவை ஏற்படுத்தும் என்பதைத் தடுக்கிறது.
- தரவை DOM கூறுகளுடன் மேப்பிங் செய்தல்: declarative framework இல்லாத சூழ்நிலைகளில், நீங்கள் சில தரவுகளை ஒரு DOM கூறுடன் தொடர்புபடுத்த விரும்பலாம். நீங்கள் அதை DOM கூறுகளை key ஆகக் கொண்ட ஒரு map-ல் சேமித்தால், உறுப்பு உங்கள் map-ல் இருக்கும்போது அது DOM-லிருந்து அகற்றப்பட்டால் நினைவக கசிவை உருவாக்கலாம். `WeakMap` இங்கே ஒரு சிறந்த தேர்வாகும், ஆனால் கொள்கை ஒன்றுதான்: தரவின் ஆயுட்காலம் உறுப்பின் ஆயுட்காலத்துடன் இணைக்கப்பட்டுள்ளது, மற்றொன்று அல்ல.
எப்போது கிளாசிக் Observer-உடன் நிற்க வேண்டும்
- இறுக்கமாக இணைக்கப்பட்ட ஆயுட்காலங்கள்: subject மற்றும் அதன் observers எப்போதும் ஒன்றாக அல்லது ஒரே scope-க்குள் உருவாக்கப்பட்டு அழிக்கப்பட்டால், `WeakRef`-ன் கூடுதல் செலவு மற்றும் சிக்கல் தேவையில்லை. ஒரு எளிய, வெளிப்படையான `unsubscribe()` அழைப்பு மிகவும் படிக்கக்கூடியதாகவும் கணிக்கக்கூடியதாகவும் இருக்கும்.
- செயல்திறன்-முக்கியமான Hot Paths: `deref()` முறைக்கு ஒரு சிறிய ஆனால் பூஜ்ஜியமற்ற செயல்திறன் செலவு உள்ளது. நீங்கள் ஆயிரக்கணக்கான observers-க்கு ஒரு வினாடிக்கு நூற்றுக்கணக்கான முறை அறிவித்தால் (எ.கா., விளையாட்டு லூப் அல்லது உயர் அதிர்வெண் தரவு காட்சிப்படுத்தலில்), நேரடி குறிப்புகளுடன் கூடிய கிளாசிக் செயல்படுத்தல் வேகமாக இருக்கும்.
- எளிய பயன்பாடுகள் மற்றும் Scripts: பயன்பாட்டின் ஆயுட்காலம் குறுகியதாகவும் நினைவக மேலாண்மை ஒரு குறிப்பிடத்தக்க கவலையாக இல்லாத சிறிய பயன்பாடுகள் அல்லது ஸ்கிரிப்டுகளுக்கு, கிளாசிக் pattern செயல்படுத்துவதற்கும் புரிந்துகொள்வதற்கும் எளிதானது. தேவையில்லாத சிக்கலை சேர்க்க வேண்டாம்.
- நிர்ணயிக்கக்கூடிய தூய்மைப்படுத்தல் தேவைப்படும்போது: ஒரு observer துண்டிக்கப்படும் சரியான நேரத்தில் ஒரு செயலைச் செய்ய நீங்கள் (எ.கா., ஒரு counter-ஐ புதுப்பித்தல், ஒரு குறிப்பிட்ட வன்பொருள் வளத்தை வெளியிடுதல்) வேண்டும் ஒரு கையேடு `unsubscribe()` முறையைப் பயன்படுத்தவும். `FinalizationRegistry`-ன் நிர்ணயிக்கப்படாத தன்மை, கணிக்கக்கூடிய வகையில் செயல்படுத்தப்பட வேண்டிய தர்க்கத்திற்கு அதை பொருத்தமற்றதாக்குகிறது.
மென்பொருள் கட்டமைப்புக்கான பரந்த தாக்கங்கள்
JavaScript போன்ற ஒரு உயர்-நிலை மொழியில் பலவீனமான குறிப்புகளின் அறிமுகம், தளத்தின் முதிர்ச்சியைக் குறிக்கிறது. குறிப்பாக நீண்ட காலம் இயங்கும் பயன்பாடுகளுக்கு மிகவும் சிக்கலான மற்றும் நிலைத்தன்மை வாய்ந்த அமைப்புகளை உருவாக்க இது டெவலப்பர்களை அனுமதிக்கிறது.
- உண்மையான decoupling: இடைமுகத்தை தாண்டி இது ஒரு நிலைக்கு decoupling-ஐ செயல்படுத்துகிறது. நாம் கூறுகளின் ஆயுட்காலங்களை கூட decoupling செய்ய முடியும். observer-கள் எப்போது உருவாக்கப்படுகின்றன அல்லது அழிக்கப்படுகின்றன என்பதைப் பற்றி subject இனி எதுவும் அறியத் தேவையில்லை.
- வடிவமைப்பால் நிலைத்தன்மை: நிரலாளர் பிழைகளுக்கு இது மிகவும் நிலைத்தன்மை வாய்ந்த அமைப்புகளை உருவாக்க உதவுகிறது. மறக்கப்பட்ட `unsubscribe()` அழைப்பு, கண்டறிய கடினமாக இருக்கும் ஒரு பொதுவான பிழை. இந்த pattern பிழைகளின் முழு வகுப்பைக் குறைக்கிறது.
- Framework மற்றும் Library எழுத்தாளர்களை செயல்படுத்துதல்: பிற டெவலப்பர்களுக்கான framework-கள், library-கள் அல்லது platform-களை உருவாக்குபவர்களுக்கு, இந்த கருவிகள் மதிப்புமிக்கவை. அவை library-களைப் பயன்படுத்துபவர்களால் தவறாகப் பயன்படுத்தப்படும் வாய்ப்பு குறைவான வலுவான API-களை உருவாக்க அனுமதிக்கின்றன, ஒட்டுமொத்தமாக மிகவும் நிலையான பயன்பாடுகளுக்கு வழிவகுக்கிறது.
முடிவுரை: நவீன JavaScript டெவலப்பருக்கான சக்திவாய்ந்த கருவி
கிளாசிக் Observer pattern என்பது மென்பொருள் வடிவமைப்பின் ஒரு அடிப்படை கட்டுமானத் தொகுதியாகும், ஆனால் வலுவான குறிப்புகளின் மீதான அதன் நம்பிக்கை, JavaScript பயன்பாடுகளில் நுட்பமான மற்றும் எரிச்சலூட்டும் நினைவக கசிவுகளின் ஆதாரமாக இருந்து வருகிறது. ES2021-ல் `WeakRef` மற்றும் `FinalizationRegistry`-ன் வருகையுடன், இந்த வரம்பை சமாளிக்க இப்போது நமக்கு கருவிகள் உள்ளன.
நாம் நீண்ட காலம் நீடிக்கும் சேவைகள் மற்றும் தற்காலிக கூறுகளுக்கு இடையிலான தொடர்பை நிர்வகிப்பது போன்ற சரியான பிரச்சனைகளுக்குப் பயன்படுத்தும்போது, WeakRef Observer pattern ஒரு விதிவிலக்காக சக்திவாய்ந்த நுட்பமாகும். அதைக் கற்றுக்கொள்வதன் மூலம், நீங்கள் மிகவும் வலுவான, திறமையான மற்றும் அளவிடக்கூடிய JavaScript பயன்பாடுகளை எழுதலாம், இது நவீன, மாறும் வலையின் தேவைகளைப் பூர்த்தி செய்யத் தயாராக உள்ளது.