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