| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 2613a9c commit c02a7e7
2 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -5,6 +5,7 @@ const { | |||
| 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 | } | |
| 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