4
4
ArrayPrototypeIndexOf,
5
5
ArrayPrototypePush,
6
6
ArrayPrototypeSplice,
7
+ SafeFinalizationRegistry,
7
8
ObjectGetPrototypeOf,
8
9
ObjectSetPrototypeOf,
9
10
Promise,
@@ -28,14 +29,29 @@ const { triggerUncaughtException } = internalBinding('errors');
28
29
29
30
const { WeakReference } = internalBinding ( 'util' ) ;
30
31
31
- function decRef ( channel ) {
32
- if ( channels . get ( channel . name ) . decRef ( ) === 0 ) {
33
- channels . delete ( channel . name ) ;
32
+ // Can't delete when weakref count reaches 0 as it could increment again.
33
+ // Only GC can be used as a valid time to clean up the channels map.
34
+ class WeakRefMap extends SafeMap {
35
+ #finalizers = new SafeFinalizationRegistry ( ( key ) => {
36
+ this . delete ( key ) ;
37
+ } ) ;
38
+
39
+ set ( key , value ) {
40
+ this . #finalizers. register ( value , key ) ;
41
+ return super . set ( key , new WeakReference ( value ) ) ;
34
42
}
35
- }
36
43
37
- function incRef ( channel ) {
38
- channels . get ( channel . name ) . incRef ( ) ;
44
+ get ( key ) {
45
+ return super . get ( key ) ?. get ( ) ;
46
+ }
47
+
48
+ incRef ( key ) {
49
+ return super . get ( key ) ?. incRef ( ) ;
50
+ }
51
+
52
+ decRef ( key ) {
53
+ return super . get ( key ) ?. decRef ( ) ;
54
+ }
39
55
}
40
56
41
57
function markActive ( channel ) {
@@ -80,7 +96,7 @@ class ActiveChannel {
80
96
subscribe ( subscription ) {
81
97
validateFunction ( subscription , 'subscription' ) ;
82
98
ArrayPrototypePush ( this . _subscribers , subscription ) ;
83
- incRef ( this ) ;
99
+ channels . incRef ( this . name ) ;
84
100
}
85
101
86
102
unsubscribe ( subscription ) {
@@ -89,15 +105,15 @@ class ActiveChannel {
89
105
90
106
ArrayPrototypeSplice ( this . _subscribers , index , 1 ) ;
91
107
92
- decRef ( this ) ;
108
+ channels . decRef ( this . name ) ;
93
109
maybeMarkInactive ( this ) ;
94
110
95
111
return true ;
96
112
}
97
113
98
114
bindStore ( store , transform ) {
99
115
const replacing = this . _stores . has ( store ) ;
100
- if ( ! replacing ) incRef ( this ) ;
116
+ if ( ! replacing ) channels . incRef ( this . name ) ;
101
117
this . _stores . set ( store , transform ) ;
102
118
}
103
119
@@ -108,7 +124,7 @@ class ActiveChannel {
108
124
109
125
this . _stores . delete ( store ) ;
110
126
111
- decRef ( this ) ;
127
+ channels . decRef ( this . name ) ;
112
128
maybeMarkInactive ( this ) ;
113
129
114
130
return true ;
@@ -153,7 +169,7 @@ class Channel {
153
169
this . _stores = undefined ;
154
170
this . name = name ;
155
171
156
- channels . set ( name , new WeakReference ( this ) ) ;
172
+ channels . set ( name , this ) ;
157
173
}
158
174
159
175
static [ SymbolHasInstance ] ( instance ) {
@@ -191,12 +207,10 @@ class Channel {
191
207
}
192
208
}
193
209
194
- const channels = new SafeMap ( ) ;
210
+ const channels = new WeakRefMap ( ) ;
195
211
196
212
function channel ( name ) {
197
- let channel ;
198
- const ref = channels . get ( name ) ;
199
- if ( ref ) channel = ref . get ( ) ;
213
+ const channel = channels . get ( name ) ;
200
214
if ( channel ) return channel ;
201
215
202
216
if ( typeof name !== 'string' && typeof name !== 'symbol' ) {
@@ -215,12 +229,8 @@ function unsubscribe(name, subscription) {
215
229
}
216
230
217
231
function hasSubscribers ( name ) {
218
- let channel ;
219
- const ref = channels . get ( name ) ;
220
- if ( ref ) channel = ref . get ( ) ;
221
- if ( ! channel ) {
222
- return false ;
223
- }
232
+ const channel = channels . get ( name ) ;
233
+ if ( ! channel ) return false ;
224
234
225
235
return channel . hasSubscribers ;
226
236
}
0 commit comments