|
3 | 3 | const { |
4 | 4 | ArrayPrototypeIndexOf, |
5 | 5 | ArrayPrototypePush, |
| 6 | + ArrayPrototypeSome, |
6 | 7 | ArrayPrototypeSplice, |
7 | 8 | ObjectCreate, |
8 | 9 | ObjectGetPrototypeOf, |
@@ -160,43 +161,100 @@ class StoreBinding { |
160 | 161 |
|
161 | 162 | // TODO(qard): figure out if putting everything on the channel has the same GC |
162 | 163 | // issue as channel.subscribe(...) did. |
163 | | -class StorageChannel { |
164 | | - constructor(name) { |
165 | | - this._enter = channel(`${name}.enter-store`); |
166 | | - this._exit = channel(`${name}.exit-store`); |
167 | | - this.kBinding = Symbol('binding'); |
| 164 | +class ActiveStorageChannel { |
| 165 | + get hasSubscribers () { |
| 166 | + return true; |
168 | 167 | } |
169 | 168 |
|
170 | | - isBoundToStore (store) { |
171 | | - return !!store[this.kBinding]; |
| 169 | + isBoundToStore(store) { |
| 170 | + return ArrayPrototypeSome(this.bindings, v => v.store === store); |
172 | 171 | } |
173 | 172 |
|
174 | 173 | bindStore(store, build) { |
175 | | - if (this.isBoundToStore(store)) return; |
176 | | - const binding = new StoreBinding(store, build); |
177 | | - store[this.kBinding] = binding; |
178 | | - this._enter.subscribe(binding.onEnter); |
179 | | - this._exit.subscribe(binding.onExit); |
| 174 | + if (this.isBoundToStore(store)) return false; |
| 175 | + ArrayPrototypePush(this.bindings, new StoreBinding(store, build)); |
| 176 | + return true; |
180 | 177 | } |
181 | 178 |
|
182 | 179 | unbindStore(store) { |
183 | | - if (!this.isBoundToStore(store)) return; |
184 | | - const binding = store[this.kBinding]; |
185 | | - this._enter.unsubscribe(binding.onEnter); |
186 | | - this._exit.unsubscribe(binding.onExit); |
187 | | - delete store[this.kBinding]; |
| 180 | + if (!this.isBoundToStore(store)) return false; |
| 181 | + |
| 182 | + let found = false; |
| 183 | + for (let index = 0; index < this.bindings.length; index++) { |
| 184 | + if (this.bindings[index].store === store) { |
| 185 | + ArrayPrototypeSplice(this.bindings, index, 1); |
| 186 | + found = true; |
| 187 | + break; |
| 188 | + } |
| 189 | + } |
| 190 | + |
| 191 | + if (!this.bindings.length) { |
| 192 | + ObjectSetPrototypeOf(this, StorageChannel.prototype); |
| 193 | + this.bindings = undefined; |
| 194 | + } |
| 195 | + |
| 196 | + return found; |
| 197 | + } |
| 198 | + |
| 199 | + _enter(data) { |
| 200 | + for (const binding of this.bindings) { |
| 201 | + binding.onEnter(data); |
| 202 | + } |
| 203 | + } |
| 204 | + |
| 205 | + _exit() { |
| 206 | + for (const binding of this.bindings) { |
| 207 | + binding.onExit(); |
| 208 | + } |
188 | 209 | } |
189 | 210 |
|
190 | 211 | run(data, fn) { |
191 | | - this._enter.publish(data); |
| 212 | + this._enter(data); |
192 | 213 | try { |
193 | 214 | return fn(); |
194 | 215 | } finally { |
195 | | - this._exit.publish(); |
| 216 | + this._exit(); |
196 | 217 | } |
197 | 218 | } |
198 | 219 | } |
199 | 220 |
|
| 221 | +class StorageChannel { |
| 222 | + constructor() { |
| 223 | + this.bindings = undefined; |
| 224 | + } |
| 225 | + |
| 226 | + static [SymbolHasInstance](instance) { |
| 227 | + const prototype = ObjectGetPrototypeOf(instance); |
| 228 | + return prototype === StorageChannel.prototype || |
| 229 | + prototype === ActiveStorageChannel.prototype; |
| 230 | + } |
| 231 | + |
| 232 | + get hasSubscribers() { |
| 233 | + return false; |
| 234 | + } |
| 235 | + |
| 236 | + isBoundToStore(_) { |
| 237 | + return false; |
| 238 | + } |
| 239 | + |
| 240 | + bindStore(store, build) { |
| 241 | + ObjectSetPrototypeOf(this, ActiveStorageChannel.prototype); |
| 242 | + this.bindings = []; |
| 243 | + return this.bindStore(store, build); |
| 244 | + } |
| 245 | + |
| 246 | + unbindStore(_) { |
| 247 | + return false; |
| 248 | + } |
| 249 | + |
| 250 | + _enter(_) {} |
| 251 | + _exit() {} |
| 252 | + |
| 253 | + run(_, fn) { |
| 254 | + return fn(); |
| 255 | + } |
| 256 | +} |
| 257 | + |
200 | 258 | const storageChannels = ObjectCreate(null); |
201 | 259 |
|
202 | 260 | function storageChannel(name) { |
|
0 commit comments