| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 4f78233 commit 88f9ebb
2 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -4,6 +4,7 @@ const { | |||
| 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 | } | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -42,3 +42,10 @@ assert.ok(!dc.unsubscribe(name, subscriber)); | |||
| 42 | 42 | assert.throws(() => { | |
| 43 | 43 | dc.subscribe(name, null); | |
| 44 | 44 | }, { code: 'ERR_INVALID_ARG_TYPE' }); | |
| 45 | + | ||
| 46 | + // Reaching zero subscribers should not delete from the channels map as there | ||
| 47 | + // will be no more weakref to incRef if another subscribe happens while the | ||
| 48 | + // channel object itself exists. | ||
| 49 | + channel.subscribe(subscriber); | ||
| 50 | + channel.unsubscribe(subscriber); | ||
| 51 | + channel.subscribe(subscriber); | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments