JavaScriptã®WeakRefãšFinalizationRegistryãæŽ»çšããŠãã¡ã¢ãªå¹çã®è¯ããªãã¶ãŒããŒãã¿ãŒã³ãäœæããæ¹æ³ãæ·±ãæãäžããŸããå€§èŠæš¡ã¢ããªã±ãŒã·ã§ã³ã§ã®ã¡ã¢ãªãªãŒã¯ãé²ããŸãã
JavaScript WeakRefãªãã¶ãŒããŒãã¿ãŒã³ïŒã¡ã¢ãªãæèããã€ãã³ãã·ã¹ãã ã®æ§ç¯
çŸä»£ã®ãŠã§ãéçºã®äžçã§ã¯ãã·ã³ã°ã«ããŒãžã¢ããªã±ãŒã·ã§ã³ïŒSPAïŒããåçã§ã¬ã¹ãã³ã·ããªãŠãŒã¶ãŒãšã¯ã¹ããªãšã³ã¹ãæ§ç¯ããããã®æšæºãšãªã£ãŠããŸãããããã®ã¢ããªã±ãŒã·ã§ã³ã¯å€ãã®å Žåãé·æéå®è¡ãããè€éãªç¶æ ã管çããç¡æ°ã®ãŠãŒã¶ãŒã€ã³ã¿ã©ã¯ã·ã§ã³ãåŠçããŸãããããããã®é·å¯¿åœã«ã¯é ããã³ã¹ãã䌎ããŸããããã¯ãã¡ã¢ãªãªãŒã¯ã®ãªã¹ã¯ã®å¢å€§ã§ããã¡ã¢ãªãªãŒã¯ãšã¯ãã¢ããªã±ãŒã·ã§ã³ãäžèŠã«ãªã£ãã¡ã¢ãªãä¿æãç¶ããããšã§ãæéã®çµéãšãšãã«ããã©ãŒãã³ã¹ãäœäžããåäœã®é å»¶ããã©ãŠã¶ã®ã¯ã©ãã·ã¥ã貧匱ãªãŠãŒã¶ãŒãšã¯ã¹ããªãšã³ã¹ã«ã€ãªããå¯èœæ§ããããŸãããããã®ãªãŒã¯ã®æãäžè¬çãªåå ã®1ã€ã¯ãåºæ¬çãªãã¶ã€ã³ãã¿ãŒã³ã§ãããªãã¶ãŒããŒãã¿ãŒã³ã«ãããŸãã
ãªãã¶ãŒããŒãã¿ãŒã³ã¯ãã€ãã³ãé§ååã¢ãŒããã¯ãã£ã®åºç€ã§ããããªããžã§ã¯ãïŒãªãã¶ãŒããŒïŒãäžå€®ã®ãªããžã§ã¯ãïŒãµããžã§ã¯ãïŒããã®æŽæ°ã賌èªããŠåä¿¡ã§ããããã«ããŸãããšã¬ã¬ã³ãã§ã·ã³ãã«ã§ãéåžžã«äŸ¿å©ã§ãããããããã®å€å žçãªå®è£ ã«ã¯éå€§ãªæ¬ é¥ããããŸããããã¯ããµããžã§ã¯ãããªãã¶ãŒããŒãžã®åŒ·ãåç §ãä¿æããŠããããšã§ãããªãã¶ãŒããŒãã¢ããªã±ãŒã·ã§ã³ã®ä»ã®éšåã§äžèŠã«ãªã£ãå Žåã§ããéçºè ãæç€ºçã«ãµããžã§ã¯ããã賌èªè§£é€ããããšãå¿ãããšãã¬ããŒãžã³ã¬ã¯ã·ã§ã³ãããããšã¯ãããŸãããã¡ã¢ãªã«éã蟌ãããããŸãŸã«ãªããã¢ããªã±ãŒã·ã§ã³ã®ããã©ãŒãã³ã¹ãæ©ãŸãã亡éãšãªããŸãã
ããã§ãææ°ã®JavaScriptãç¹ã«ECMAScript 2021ïŒES12ïŒã®æ©èœãã匷åãªãœãªã¥ãŒã·ã§ã³ãæäŸããŸããWeakRefãšFinalizationRegistryãæŽ»çšããããšã§ãèªåçã«ã¯ãªãŒã³ã¢ããããäžè¬çãªãªãŒã¯ãé²ããã¡ã¢ãªãæèãããªãã¶ãŒããŒãã¿ãŒã³ãæ§ç¯ã§ããŸãããã®èšäºã§ã¯ããã®é«åºŠãªãã¯ããã¯ã«ã€ããŠæ·±ãæãäžããŸããåé¡ã調æ»ããããŒã«ãçè§£ããå ç¢ãªå®è£ ããŒãããæ§ç¯ãããã®åŒ·åãªãã¿ãŒã³ãã°ããŒãã«ã¢ããªã±ãŒã·ã§ã³ã®ã©ãã§ããã€é©çšãã¹ãããè°è«ããŸãã
çè§£ãã¹ãæ žå¿çãªåé¡ïŒå€å žçãªãªãã¶ãŒããŒãã¿ãŒã³ãšãã®ã¡ã¢ãªãããããªã³ã
解決çãçè§£ããåã«ãåé¡ãå®å šã«ææ¡ããå¿ èŠããããŸãããªãã¶ãŒããŒãã¿ãŒã³ã¯ããããªãã·ã£ãŒ/ãµãã¹ã¯ã©ã€ããŒãã¿ãŒã³ãšããŠãç¥ãããŠãããã³ã³ããŒãã³ããåé¢ããããã«èšèšãããŠããŸããSubjectïŒãŸãã¯PublisherïŒã¯ãObserversïŒãŸãã¯SubscribersïŒãšåŒã°ããäŸåé¢ä¿ã®ãªã¹ããä¿æããŸããSubjectã®ç¶æ ãå€åãããšãéåžžãupdate()ãªã©ã®ç¹å®ã®ã¡ãœãããåŒã³åºãããšã«ãã£ãŠããã¹ãŠã®Observersã«èªåçã«éç¥ããŸãã
JavaScriptã§ã®ã·ã³ãã«ã§å€å žçãªå®è£ ãèŠãŠã¿ãŸãããã
ã·ã³ãã«ãªSubjectã®å®è£
åºæ¬çãªSubjectã¯ã©ã¹ã以äžã«ç€ºããŸãããªãã¶ãŒããŒã賌èªã賌èªè§£é€ãéç¥ããã¡ãœããããããŸãã
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}`);
}
}
é ããå±éºïŒæ®åããåç §
ãã®å®è£ ã¯ããªãã¶ãŒããŒã®ã©ã€ããµã€ã¯ã«ããŸããã«ç®¡çããŠããéããå®å šã«æ©èœããŸããåé¡ã¯ãããã§ãªãå Žåã«çºçããŸããå€§èŠæš¡ã¢ããªã±ãŒã·ã§ã³ã§ã®äžè¬çãªã·ããªãªãèããŠã¿ãŸããããããã¯ãé·å¯¿åœã®ã°ããŒãã«ããŒã¿ã¹ãã¢ïŒ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ã§ã¯ããã®çš®ã®ã¡ã¢ãªç®¡çã®èª²é¡ã«å¯ŸåŠããããã«ç¹å¥ã«èšèšããã2ã€ã®æ°æ©èœã`WeakRef`ãš`FinalizationRegistry`ãå°å ¥ãããŸããããããã¯é«åºŠãªããŒã«ã§ãããæ³šæããŠäœ¿çšããå¿ èŠããããŸããããªãã¶ãŒããŒãã¿ãŒã³ã®åé¡ã«ã¯æé©ãªãœãªã¥ãŒã·ã§ã³ã§ãã
WeakRefãšã¯ïŒ
`WeakRef`ãªããžã§ã¯ãã¯ããã®ã¿ãŒã²ãããšåŒã°ããå¥ã®ãªããžã§ã¯ããžã®åŒ±ãåç §ãä¿æããŸãã匱ãåç §ãšéåžžã®ïŒåŒ·ãïŒåç §ã®äž»ãªéãã¯æ¬¡ã®ãšããã§ãã匱ãåç §ã¯ãã¿ãŒã²ãããªããžã§ã¯ããã¬ããŒãžã³ã¬ã¯ã·ã§ã³ãããã®ãé²ããŸããã
ãªããžã§ã¯ããžã®åç §ã匱ãåç §ã®ã¿ã®å ŽåãJavaScriptãšã³ãžã³ã¯ãªããžã§ã¯ããç Žæ£ããŠã¡ã¢ãªãåå©çšã§ããŸããããã¯ãŸãã«ãªãã¶ãŒããŒã®åé¡ã解決ããããã«å¿ èŠãªãã®ã§ãã
`WeakRef`ã䜿çšããã«ã¯ããã®ã€ã³ã¹ã¿ã³ã¹ãäœæããã¿ãŒã²ãããªããžã§ã¯ããã³ã³ã¹ãã©ã¯ã¿ãŒã«æž¡ããŸããåŸã§ã¿ãŒã²ãããªããžã§ã¯ãã«ã¢ã¯ã»ã¹ããã«ã¯ã`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`ãã¬ããŒãžã³ã¬ã¯ã·ã§ã³ãããå Žåã«çºçããŸããããã¯ããããžã®åŒ·ãåç §ãããååšããªãããã§ãããã®åäœã¯ãã¡ã¢ãªãæèãããªãã¶ãŒããŒãã¿ãŒã³ã®åºç€ãšãªããŸãã
FinalizationRegistryãšã¯ïŒ
`WeakRef`ã䜿çšãããšããªããžã§ã¯ããåéã§ããŸããããã€åéãããããç¥ãããã®æç¢ºãªæ¹æ³ã¯ãããŸããã`deref()`ã宿çã«ãã§ãã¯ãããªãã¶ãŒããŒãªã¹ããã`undefined`ã®çµæãåé€ã§ããŸãããããã¯éå¹ççã§ããããã§`FinalizationRegistry`ãç»å ŽããŸãã
`FinalizationRegistry`ã䜿çšãããšãç»é²ããããªããžã§ã¯ããã¬ããŒãžã³ã¬ã¯ã·ã§ã³ãããåŸã«åŒã³åºãããã³ãŒã«ããã¯é¢æ°ãç»é²ã§ããŸããããã¯ãäºåŸã¯ãªãŒã³ã¢ããã®ã¡ã«ããºã ã§ãã
ä»çµã¿ã¯æ¬¡ã®ãšããã§ãã
- ã¯ãªãŒã³ã¢ããã³ãŒã«ããã¯ã䜿çšããŠã¬ãžã¹ããªãäœæããŸãã
- ãªããžã§ã¯ãã`register()`ã§ã¬ãžã¹ããªã«ç»é²ããŸãããŸãã`heldValue`ãæäŸããããšãã§ããŸããããã¯ããªããžã§ã¯ããåéããããšãã«ã³ãŒã«ããã¯ã«æž¡ãããããŒã¿ã§ãããã®`heldValue`ã¯ããªããžã§ã¯ãèªäœãžã®çŽæ¥åç §ã§ãã£ãŠã¯ãªããŸããããããããšãç®çãæãªãããŸãïŒ
// 1. ã¯ãªãŒã³ã¢ããã³ãŒã«ããã¯ã§ã¬ãžã¹ããªãäœæãã
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. ãªããžã§ã¯ããç»é²ããã¯ãªãŒã³ã¢ããçšã®ããŒã¯ã³ãæäŸãã
registry.register(objectToTrack, cleanupToken);
// objectToTrackã¯ããã§ã¹ã³ãŒãå€ã«ãªããŸã
})();
// å°æ¥ã®ããæç¹ã§ãGCãå®è¡ãããåŸãã³ã³ãœãŒã«ã«ã¯æ¬¡ã®ãã°ãåºåãããŸãã
// "An object has been garbage collected. Cleanup token: temp-data-123"
éèŠãªæ³šæç¹ãšãã¹ããã©ã¯ãã£ã¹
å®è£ ã«å ¥ãåã«ããããã®ããŒã«ã®æ§è³ªãçè§£ããããšãéèŠã§ããã¬ããŒãžã³ã¬ã¯ã¿ãŒã®åäœã¯ãå®è£ ã«å€§ããäŸåããéæ±ºå®çã§ããã€ãŸãïŒ
- ãªããžã§ã¯ããåéãããã¿ã€ãã³ã°ãäºæž¬ã§ããŸãããå°éäžèœã«ãªã£ãŠããæ°ç§ãæ°åããŸãã¯ãã以äžãããå ŽåããããŸãã
- `FinalizationRegistry`ã³ãŒã«ããã¯ãã¿ã€ã ãªãŒãŸãã¯äºæž¬å¯èœãªæ¹æ³ã§å®è¡ãããããšãä¿¡é Œã§ããŸããããããã¯ãã¯ãªãŒã³ã¢ããçšã§ãããéèŠãªã¢ããªã±ãŒã·ã§ã³ããžãã¯çšã§ã¯ãããŸããã
- `WeakRef`ãš`FinalizationRegistry`ãé床ã«äœ¿çšãããšãã³ãŒãã®æšè«ãé£ãããªãå¯èœæ§ããããŸãããªããžã§ã¯ãã®ã©ã€ããµã€ã¯ã«ãæç¢ºã§ç®¡çããããå Žåã¯ãåžžã«åçŽãªãœãªã¥ãŒã·ã§ã³ïŒæç€ºçãª`unsubscribe`åŒã³åºããªã©ïŒãåªå ããŠãã ããã
ãããã®æ©èœã¯ããããªããžã§ã¯ãïŒãªãã¶ãŒããŒïŒã®ã©ã€ããµã€ã¯ã«ãå¥ã®ãªããžã§ã¯ãïŒãµããžã§ã¯ãïŒããå®å šã«ç¬ç«ããŠãããäžæã§ããå Žåã«æé©ã§ãã
`WeakRefObserver`ãã¿ãŒã³ã®æ§ç¯ïŒã¹ããããã€ã¹ãããã®å®è£
次ã«ã`WeakRef`ãš`FinalizationRegistry`ãçµã¿åãããŠãã¡ã¢ãªã»ãŒããª`WeakRefSubject`ã¯ã©ã¹ãæ§ç¯ããŸãã
ã¹ããã1ïŒ`WeakRefSubject`ã¯ã©ã¹ã®æ§é
æ°ããã¯ã©ã¹ã¯ãçŽæ¥åç §ã®ä»£ããã«ããªãã¶ãŒããŒãžã®`WeakRef`ãä¿åããŸãããŸãããªãã¶ãŒããŒãªã¹ãã®èªåã¯ãªãŒã³ã¢ãããåŠçããããã®`FinalizationRegistry`ãåããŠããŸãã
class WeakRefSubject {
constructor() {
this.observers = new Set(); // åé€ã容æã«ããããã«Setã䜿çšãã
// ãã¡ã€ãã©ã€ã¶ãŒã³ãŒã«ããã¯ãç»é²æã«æäŸããä¿æãããå€ãåãåããŸãã
// ãã®å Žåãä¿æãããå€ã¯WeakRefã€ã³ã¹ã¿ã³ã¹èªäœã«ãªããŸãã
this.cleanupRegistry = new FinalizationRegistry(weakRefObserver => {
console.log('Finalizer: An observer has been garbage collected. Cleaning up...');
this.observers.delete(weakRefObserver);
});
}
}
ãªãã¶ãŒããŒãªã¹ãã«ã¯ã`Array`ã®ä»£ããã«`Set`ã䜿çšããŸããããã¯ã`Set`ããã¢ã€ãã ãåé€ããæ¹ãã`Array`ããã£ã«ã¿ãªã³ã°ãããããã¯ããã«å¹ççã§ããããïŒO(1)ã®å¹³åæéè€é床ïŒãã¯ãªãŒã³ã¢ããããžãã¯ã§åœ¹ç«ã¡ãŸãã
ã¹ããã2ïŒ`subscribe`ã¡ãœãã
`subscribe`ã¡ãœããã¯ãéæ³ãå§ãŸãå Žæã§ãããªãã¶ãŒããŒããµãã¹ã¯ã©ã€ããããšã次ã®ããã«ãªããŸãã
- ãªãã¶ãŒããŒãæã`WeakRef`ãäœæããŸãã
- ãã®`WeakRef`ã`observers`ã»ããã«è¿œå ããŸãã
- æ°ããäœæããã`WeakRef`ã`heldValue`ãšããŠäœ¿çšããŠãå ã®ãªãã¶ãŒããŒãªããžã§ã¯ãã`FinalizationRegistry`ã«ç»é²ããŸãã
// WeakRefSubjectã¯ã©ã¹å ...
subscribe(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);
// å ã®ãªãã¶ãŒããŒãªããžã§ã¯ããç»é²ããŸããåéããããšã
// ãã¡ã€ãã©ã€ã¶ãŒã¯`weakRefObserver`ãåŒæ°ãšããŠåŒã³åºãããŸãã
this.cleanupRegistry.register(observer, weakRefObserver);
console.log('An observer has subscribed.');
}
ãã®èšå®ã«ãããå·§åŠãªã«ãŒããäœæãããŸãããµããžã§ã¯ãã¯ãªãã¶ãŒããŒãžã®åŒ±ãåç §ãä¿æããŸããã¬ãžã¹ããªã¯ãã¬ããŒãžã³ã¬ã¯ã·ã§ã³ããããŸã§ããªãã¶ãŒããŒãžã®åŒ·ãåç §ãïŒå éšçã«ïŒä¿æããŸããåéããããšãã¬ãžã¹ããªã®ã³ãŒã«ããã¯ã匱ãåç §ã€ã³ã¹ã¿ã³ã¹ã§ããªã¬ãŒãããããã䜿çšããŠ`observers`ã»ãããã¯ãªãŒã³ã¢ããã§ããŸãã
ã¹ããã3ïŒ`unsubscribe`ã¡ãœãã
èªåã¯ãªãŒã³ã¢ããããã£ãŠããæ±ºå®çãªåé€ãå¿ èŠãªå Žåã«åããŠãæåã®`unsubscribe`ã¡ãœãããæäŸããå¿ èŠããããŸãããã®ã¡ãœããã§ã¯ãå`WeakRef`ãéåç §ããåé€ãããªãã¶ãŒããŒãšæ¯èŒããŠãã»ããå ã®æ£ãã`WeakRef`ãèŠã€ããå¿ èŠããããŸãã
// 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);
// éèŠïŒãã¡ã€ãã©ã€ã¶ãŒããã®ç»é²ãè§£é€ããå¿ èŠããããŸã
// åŸã§äžèŠãªã³ãŒã«ããã¯ãå®è¡ãããªãããã«ããŸãã
this.cleanupRegistry.unregister(observer);
console.log('An observer has unsubscribed manually.');
}
}
ã¹ããã4ïŒ`notify`ã¡ãœãã
`notify`ã¡ãœããã¯ã`WeakRef`ã®ã»ãããå埩åŠçããŸããããããã«ã€ããŠã`deref()`ã詊è¡ããŠãå®éã®ãªãã¶ãŒããŒãªããžã§ã¯ããååŸããŸãã`deref()`ãæåããå Žåããªãã¶ãŒããŒããŸã ã¢ã¯ãã£ãã§ããããšãæå³ãããã®`update`ã¡ãœãããåŒã³åºãããšãã§ããŸãã`undefined`ãè¿ãããå Žåããªãã¶ãŒããŒã¯åéãããŠãããåã«ç¡èŠã§ããŸãã`FinalizationRegistry`ã¯ãæçµçã«ãã®`WeakRef`ãã»ããããåé€ããŸãã
// WeakRefSubjectã¯ã©ã¹å ...
notify(data) {
console.log('Notifying observers...');
for (const weakRefObserver of this.observers) {
const observer = weakRefObserver.deref();
if (observer) {
// ãªãã¶ãŒããŒã¯ãŸã ã¢ã¯ãã£ãã§ã
observer.update(data);
} else {
// ãªãã¶ãŒããŒã¯ã¬ããŒãžã³ã¬ã¯ã·ã§ã³ãããŸããã
// FinalizationRegistryã¯ãã®weakRefãã»ããããåé€ããŸãã
console.log('Found a dead observer reference during notification.');
}
}
}
ãã¹ãŠããŸãšããïŒå®è·µçãªäŸ
UIã³ã³ããŒãã³ãã®ã·ããªãªã忀èšããŸãããä»åã¯æ°ãã`WeakRefSubject`ã䜿çšããŸããç°¡åã«ããããã«ã以åãšåã`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`ã«ãã£ãŠã®ã¿åç §ãããŸããããã匱ãåç §ã§ããããããªããžã§ã¯ãã¯ã¬ããŒãžã³ã¬ã¯ã·ã§ã³ã®å¯Ÿè±¡ã«ãªããŸãã
ã¬ããŒãžã³ã¬ã¯ã¿ãŒãæçµçã«å®è¡ããããšïŒäºæž¬ã§ããŸããïŒã次ã®2ã€ã®ããšãèµ·ãããŸãã
- `chartWidget`ãªããžã§ã¯ããã¡ã¢ãªããåé€ãããŸãã
- `FinalizationRegistry`ã®ã³ãŒã«ããã¯ãããªã¬ãŒãããæ¬¡ã«ã`globalDataService.observers`ã»ãããããååšããªã`WeakRef`ãåé€ãããŸãã
ã¬ããŒãžã³ã¬ã¯ã¿ãŒãå®è¡ãããåŸã«`notify`ãå床åŒã³åºããšã`deref()`åŒã³åºãã¯`undefined`ãè¿ããååšããªããªãã¶ãŒããŒã¯ã¹ããããããã¢ããªã±ãŒã·ã§ã³ã¯ã¡ã¢ãªãªãŒã¯ãªãã§å¹ççã«å®è¡ããç¶ããŸãããªãã¶ãŒããŒã®ã©ã€ããµã€ã¯ã«ããµããžã§ã¯ãããåé¢ããããšã«æåããŸããã
`WeakRefObserver`ãã¿ãŒã³ã䜿çšããïŒããã³äœ¿çšããªãïŒå Žå
ãã®ãã¿ãŒã³ã¯åŒ·åã§ãããäžèœè¬ã§ã¯ãããŸãããè€éããå¢ããéæ±ºå®çãªåäœã«äŸåããŸãããžã§ãã«é©ããããŒã«ã§ãããã©ãããç¥ãããšãéèŠã§ãã
çæ³çãªãŠãŒã¹ã±ãŒã¹
- é·å¯¿åœã®ãµããžã§ã¯ããšç寿åœã®ãªãã¶ãŒããŒïŒãããæšæºçãªãŠãŒã¹ã±ãŒã¹ã§ããã¢ããªã±ãŒã·ã§ã³ã®ã©ã€ããµã€ã¯ã«å šäœã«ããã£ãŠååšããã°ããŒãã«ãµãŒãã¹ãããŒã¿ã¹ãã¢ããŸãã¯ãã£ãã·ã¥ïŒãµããžã§ã¯ãïŒãšã倿°ã®UIã³ã³ããŒãã³ããäžæçãªã¯ãŒã«ãŒããŸãã¯ãã©ã°ã€ã³ïŒãªãã¶ãŒããŒïŒãé »ç¹ã«äœæããã³ç Žæ£ãããŸãã
- ãã£ãã·ã³ã°ã¡ã«ããºã ïŒè€éãªãªããžã§ã¯ããèšç®ãããçµæã«ããããããã£ãã·ã¥ãæ³åããŠãã ãããããŒãªããžã§ã¯ãã«`WeakRef`ã䜿çšã§ããŸããå ã®ãªããžã§ã¯ããã¢ããªã±ãŒã·ã§ã³ã®ä»ã®éšåããã¬ããŒãžã³ã¬ã¯ã·ã§ã³ãããå Žåã`FinalizationRegistry`ã¯ãã£ãã·ã¥å ã®å¯Ÿå¿ãããšã³ããªãèªåçã«ã¯ãªãŒã³ã¢ããããŠãã¡ã¢ãªã®è¥å€§åãé²ãããšãã§ããŸãã
- ãã©ã°ã€ã³ããã³æ¡åŒµã¢ãŒããã¯ãã£ïŒãµãŒãããŒãã£ã¢ãžã¥ãŒã«ãã€ãã³ãããµãã¹ã¯ã©ã€ãã§ããã³ã¢ã·ã¹ãã ãæ§ç¯ããå Žåã`WeakRefObserver`ã䜿çšãããšãå埩æ§ã®ã¬ã€ã€ãŒã远å ãããŸãããµãã¹ã¯ã©ã€ãè§£é€ãå¿ããäžååã«èšè¿°ããããã©ã°ã€ã³ããã³ã¢ã¢ããªã±ãŒã·ã§ã³ã§ã¡ã¢ãªãªãŒã¯ãåŒãèµ·ããã®ãé²ããŸãã
- ããŒã¿ãDOMèŠçŽ ã«ãããã³ã°ïŒå®£èšçãªãã¬ãŒã ã¯ãŒã¯ããªãã·ããªãªã§ã¯ãäžéšã®ããŒã¿ãDOMèŠçŽ ã«é¢é£ä»ããå ŽåããããŸããDOMèŠçŽ ãããŒãšããŠãããã«ä¿åãããšãèŠçŽ ãDOMããåé€ãããŠããããã«æ®ã£ãŠããå Žåã«ãã¡ã¢ãªãªãŒã¯ãçºçããå¯èœæ§ããããŸãã`WeakMap`ã¯ããã§ã¯ããé©åãªéžæè¢ã§ãããååã¯åãã§ããããŒã¿ã®ã©ã€ããµã€ã¯ã«ã¯ãèŠçŽ ã®ã©ã€ããµã€ã¯ã«ã«é¢é£ä»ããããå¿ èŠãããããã®éã§ã¯ãããŸããã
å€å žçãªãªãã¶ãŒããŒã䜿çšããå Žå
- ç·å¯ã«çµåãããã©ã€ããµã€ã¯ã«ïŒãµããžã§ã¯ããšãã®ãªãã¶ãŒããŒãåžžã«äžç·ã«ããŸãã¯åãã¹ã³ãŒãå ã§äœæããã³ç Žæ£ãããå Žåã`WeakRef`ã®ãªãŒããŒããããšè€éãã¯äžèŠã§ããåçŽã§æç€ºçãª`unsubscribe()`åŒã³åºãã®æ¹ãèªã¿ããããäºæž¬å¯èœã§ãã
- ããã©ãŒãã³ã¹ãéèŠãªããããã¹ïŒ`deref()`ã¡ãœããã«ã¯ãå°ãããŠããŒãã§ã¯ãªãããã©ãŒãã³ã¹ã³ã¹ãããããŸãã1ç§ãããæ°çŸåãæ°å人ã®ãªãã¶ãŒããŒã«éç¥ããå ŽåïŒããšãã°ãã²ãŒã ã«ãŒããé«é »åºŠã®ããŒã¿èŠèŠåãªã©ïŒãçŽæ¥åç §ãæã€å€å žçãªå®è£ ã®æ¹ãé«éã«ãªããŸãã
- ã·ã³ãã«ãªã¢ããªã±ãŒã·ã§ã³ãšã¹ã¯ãªããïŒã¢ããªã±ãŒã·ã§ã³ã®æå¹æéãçããã¡ã¢ãªç®¡çãéèŠãªæžå¿µäºé ã§ã¯ãªãå°èŠæš¡ãªã¢ããªã±ãŒã·ã§ã³ãŸãã¯ã¹ã¯ãªããã®å Žåãå€å žçãªãã¿ãŒã³ã®æ¹ãå®è£ ãšçè§£ã容æã§ããäžèŠãªå Žæã«è€éãã远å ããªãã§ãã ããã
- 決å®çãªã¯ãªãŒã³ã¢ãããå¿ èŠãªå ŽåïŒãªãã¶ãŒããŒããã¿ãããããç¬éã«ã¢ã¯ã·ã§ã³ãå®è¡ããå¿ èŠãããå ŽåïŒããšãã°ãã«ãŠã³ã¿ãŒã®æŽæ°ãç¹å®ã®ããŒããŠã§ã¢ãªãœãŒã¹ã®è§£æŸãªã©ïŒãæåã®`unsubscribe()`ã¡ãœããã䜿çšããå¿ èŠããããŸãã`FinalizationRegistry`ã®é決å®çãªæ§è³ªã«ãããäºæž¬å¯èœã«å®è¡ããå¿ èŠãããããžãã¯ã«ã¯é©ããŠããŸããã
ãœãããŠã§ã¢ã¢ãŒããã¯ãã£ãžã®ããåºç¯ãªåœ±é¿
髿°ŽæºèšèªïŒJavaScriptãªã©ïŒãžã®åŒ±ãåç §ã®å°å ¥ã¯ããã©ãããã©ãŒã ã®æç床ã瀺ããŠããŸããããã«ãããéçºè ã¯ãç¹ã«é·æéå®è¡ãããã¢ããªã±ãŒã·ã§ã³ã®å ŽåãããæŽç·Žãããå埩åã®ããã·ã¹ãã ãæ§ç¯ã§ããŸãããã®ãã¿ãŒã³ã¯ãã¢ãŒããã¯ãã£æèã®è»¢æãä¿ããŸãã
- çã®åé¢ïŒã€ã³ã¿ãŒãã§ã€ã¹ãè¶ ããã¬ãã«ã®åé¢ãå¯èœã«ããŸããã³ã³ããŒãã³ãã®ã©ã€ããµã€ã¯ã«ãåé¢ã§ããããã«ãªããŸããããµããžã§ã¯ãã¯ããªãã¶ãŒããŒããã€äœæãŸãã¯ç Žæ£ãããããç¥ãå¿ èŠããªããªããŸããã
- èšèšã«ããå埩åïŒããã°ã©ããŒã®ãšã©ãŒã«å¯ŸããŠããå埩åã®ããã·ã¹ãã ãæ§ç¯ããã®ã«åœ¹ç«ã¡ãŸããå¿ãããã`unsubscribe()`åŒã³åºãã¯ã远跡ãå°é£ãªäžè¬çãªãã°ã§ãããã®ãã¿ãŒã³ã¯ããã®ãšã©ãŒã®ã¯ã©ã¹å šäœã軜æžããŸãã
- ãã¬ãŒã ã¯ãŒã¯ãšã©ã€ãã©ãªã®äœæè ã®æå¹åïŒä»ã®éçºè åãã®ãã¬ãŒã ã¯ãŒã¯ãã©ã€ãã©ãªããŸãã¯ãã©ãããã©ãŒã ãæ§ç¯ããå Žåããããã®ããŒã«ã¯éåžžã«è²Žéã§ããã©ã€ãã©ãªã®å©çšè ã誀çšãã«ããå ç¢ãªAPIãäœæã§ãããããå šäœãšããŠããå®å®ããã¢ããªã±ãŒã·ã§ã³ã«ã€ãªãããŸãã
çµè«ïŒçŸä»£ã®JavaScriptéçºè åãã®åŒ·åãªããŒã«
å€å žçãªãªãã¶ãŒããŒãã¿ãŒã³ã¯ãœãããŠã§ã¢èšèšã®åºæ¬çãªæ§æèŠçŽ ã§ããã匷ãåç §ãžã®äŸåã¯ãJavaScriptã¢ããªã±ãŒã·ã§ã³ã«ããã埮åŠã§äžæºã®æ®ãã¡ã¢ãªãªãŒã¯ã®é·å¹Žã®åå ã§ãããES2021ã§ã®`WeakRef`ãš`FinalizationRegistry`ã®ç»å Žã«ããããã®å¶éãå æããããã®ããŒã«ãæã«å ¥ããŸããã
æ®åããåç §ãšããæ ¹æ¬çãªåé¡ã®çè§£ãããå®å šãªãã¡ã¢ãªãæèãã`WeakRefSubject`ããŒãããæ§ç¯ãããŸã§ã®éã®ããæ©ãã§ããŸããã`WeakRef`ã䜿çšãããšããªããžã§ã¯ãããç£èŠããããŠããŠãã¬ããŒãžã³ã¬ã¯ã·ã§ã³ã§ããããšãããã³`FinalizationRegistry`ããªãã¶ãŒããŒãªã¹ããå ã®ç¶æ ã«ä¿ã€ããã®èªååãããã¯ãªãŒã³ã¢ããã¡ã«ããºã ãæäŸããæ¹æ³ãèŠãŠããŸããã
ãã ãã倧ããªãåã«ã¯å€§ããªã責任ã䌎ããŸãããããã¯é«åºŠãªæ©èœã§ããããã®é決å®çãªæ§è³ªã«ã¯æ éãªæ€èšãå¿ èŠã§ãããããã¯ãåªããã¢ããªã±ãŒã·ã§ã³èšèšãšå€åãªã©ã€ããµã€ã¯ã«ç®¡çã®ä»£æ¿ã§ã¯ãããŸããããã ããé·å¯¿åœã®ãµãŒãã¹ãšäžæçãªã³ã³ããŒãã³ãéã®éä¿¡ã®ç®¡çãªã©ãé©åãªåé¡ã«é©çšãããšãWeakRefãªãã¶ãŒããŒãã¿ãŒã³ã¯éåžžã«åŒ·åãªææ³ã§ãããããç¿åŸããããšã§ãçŸä»£ã®åçãªãŠã§ãã®èŠæ±ã«å¿ããæºåãã§ããŠãããããå ç¢ã§å¹ççã§ã¹ã±ãŒã©ãã«ãªJavaScriptã¢ããªã±ãŒã·ã§ã³ãäœæã§ããŸãã