@@ -49,6 +49,17 @@ function getSuppressionsStorage() {
4949function withSuppressionsContext ( set , fn , thisArg , args ) {
5050 return getSuppressionsStorage ( ) . run ( set , fn . bind ( thisArg ) , ...args ) ;
5151}
52+
53+ function validateBypassKey ( value , name ) {
54+ if ( value == null ) {
55+ throw new ERR_INVALID_ARG_TYPE ( name , [ 'object' , 'symbol' ] , value ) ;
56+ }
57+ const type = typeof value ;
58+ if ( type !== 'object' && type !== 'symbol' ) {
59+ throw new ERR_INVALID_ARG_TYPE ( name , [ 'object' , 'symbol' ] , value ) ;
60+ }
61+ }
62+
5263// Can't delete when weakref count reaches 0 as it could increment again.
5364// Only GC can be used as a valid time to clean up the channels map.
5465class WeakRefMap extends SafeMap {
@@ -84,16 +95,23 @@ function markActive(channel) {
8495 // eslint-disable-next-line no-use-before-define
8596 ObjectSetPrototypeOf ( channel , ActiveChannel . prototype ) ;
8697 channel . _subscribers = [ ] ;
98+ channel . _bypassSubscribers = null ;
8799 channel . _stores = new SafeMap ( ) ;
100+ channel . _bypassStores = null ;
88101}
89102
90103function maybeMarkInactive ( channel ) {
91104 // When there are no more active subscribers or bound, restore to fast prototype.
92- if ( ! channel . _subscribers . length && ! channel . _stores . size ) {
105+ if ( ! channel . _subscribers . length &&
106+ ! channel . _stores . size &&
107+ ! channel . _bypassSubscribers ?. length &&
108+ ! channel . _bypassStores ?. size ) {
93109 // eslint-disable-next-line no-use-before-define
94110 ObjectSetPrototypeOf ( channel , Channel . prototype ) ;
95111 channel . _subscribers = undefined ;
96112 channel . _stores = undefined ;
113+ channel . _bypassSubscribers = undefined ;
114+ channel . _bypassStores = undefined ;
97115 }
98116}
99117
@@ -104,19 +122,33 @@ class RunStoresScope {
104122 // eslint-disable-next-line no-restricted-globals
105123 using stack = new DisposableStack ( ) ;
106124
107- // Enter stores using withScope
125+ // Normal stores — exactly as before, zero extra cost
108126 if ( activeChannel . _stores ) {
109- const activeKeys = getSuppressionsStorage ( ) . getStore ( ) ;
110127 for ( const entry of activeChannel . _stores . entries ( ) ) {
111128 const store = entry [ 0 ] ;
112- const { transform, subscriberId = null } = entry [ 1 ] ;
113-
114- // Skip this bound store if it opted into suppression and its key
115- // is active in the current async context.
116- if ( subscriberId !== null && activeKeys ?. has ( subscriberId ) ) {
117- continue ;
129+ const transform = entry [ 1 ] ;
130+ let newContext = data ;
131+ if ( transform ) {
132+ try {
133+ newContext = transform ( data ) ;
134+ } catch ( err ) {
135+ process . nextTick ( ( ) => {
136+ triggerUncaughtException ( err , false ) ;
137+ } ) ;
138+ continue ;
139+ }
118140 }
141+ stack . use ( store . withScope ( newContext ) ) ;
142+ }
143+ }
119144
145+ // Bypass stores — only entered if bypass stores exist
146+ if ( activeChannel . _bypassStores ) {
147+ const activeKeys = getSuppressionsStorage ( ) . getStore ( ) ;
148+ for ( const entry of activeChannel . _bypassStores . entries ( ) ) {
149+ const store = entry [ 0 ] ;
150+ const { transform, subscriberId } = entry [ 1 ] ;
151+ if ( activeKeys ?. has ( subscriberId ) ) continue ;
120152 let newContext = data ;
121153 if ( transform ) {
122154 try {
@@ -128,7 +160,6 @@ class RunStoresScope {
128160 continue ;
129161 }
130162 }
131-
132163 stack . use ( store . withScope ( newContext ) ) ;
133164 }
134165 }
@@ -149,95 +180,156 @@ class RunStoresScope {
149180class ActiveChannel {
150181 subscribe ( subscription , options = { } ) {
151182 validateFunction ( subscription , 'subscription' ) ;
152- const subscriberId = options && options . subscriberId !== undefined ? options . subscriberId : null ;
153- if ( subscriberId !== null ) {
154- const t = typeof subscriberId ;
155- if ( t === 'string' || t === 'number' || t === 'bigint' || t === 'boolean' ) {
156- throw new ERR_INVALID_ARG_TYPE ( 'subscriberId' , [ 'object' , 'symbol' , 'function' ] , subscriberId ) ;
183+ const subscriberId = options ?. subscriberId ;
184+
185+ if ( subscriberId !== undefined ) {
186+ validateBypassKey ( subscriberId , 'subscriberId' ) ;
187+ // Bypass path — lazy separate array
188+ if ( this . _bypassSubscribers === null ) {
189+ this . _bypassSubscribers = [ ] ;
157190 }
191+ this . _bypassSubscribers = ArrayPrototypeSlice ( this . _bypassSubscribers ) ;
192+ ArrayPrototypePush ( this . _bypassSubscribers , { handler : subscription , subscriberId } ) ;
193+ } else {
194+ // Normal path — plain function, zero extra cost
195+ this . _subscribers = ArrayPrototypeSlice ( this . _subscribers ) ;
196+ ArrayPrototypePush ( this . _subscribers , subscription ) ;
158197 }
159198
160- const handler = subscription ;
161- this . _subscribers = ArrayPrototypeSlice ( this . _subscribers ) ;
162- ArrayPrototypePush ( this . _subscribers , { handler, subscriberId } ) ;
163199 channels . incRef ( this . name ) ;
164200 if ( this . _index !== undefined ) subscriberCounts [ this . _index ] ++ ;
165201 }
166202
167203 unsubscribe ( subscription ) {
168- // Find subscriber entry by handler identity.
204+ // Check normal subscribers first
169205 let index = - 1 ;
170- for ( let i = 0 ; i < ( this . _subscribers ? .length || 0 ) ; i ++ ) {
171- if ( this . _subscribers [ i ] . handler === subscription ) {
206+ for ( let i = 0 ; i < this . _subscribers . length ; i ++ ) {
207+ if ( this . _subscribers [ i ] === subscription ) {
172208 index = i ;
173209 break ;
174210 }
175211 }
176- if ( index === - 1 ) return false ;
177212
178- const before = ArrayPrototypeSlice ( this . _subscribers , 0 , index ) ;
179- const after = ArrayPrototypeSlice ( this . _subscribers , index + 1 ) ;
180- this . _subscribers = before ;
181- ArrayPrototypePushApply ( this . _subscribers , after ) ;
213+ if ( index !== - 1 ) {
214+ const before = ArrayPrototypeSlice ( this . _subscribers , 0 , index ) ;
215+ const after = ArrayPrototypeSlice ( this . _subscribers , index + 1 ) ;
216+ this . _subscribers = before ;
217+ ArrayPrototypePushApply ( this . _subscribers , after ) ;
218+ channels . decRef ( this . name ) ;
219+ if ( this . _index !== undefined ) subscriberCounts [ this . _index ] -- ;
220+ maybeMarkInactive ( this ) ;
221+ return true ;
222+ }
182223
183- channels . decRef ( this . name ) ;
184- if ( this . _index !== undefined ) subscriberCounts [ this . _index ] -- ;
185- maybeMarkInactive ( this ) ;
224+ // Check bypass subscribers
225+ if ( this . _bypassSubscribers !== null ) {
226+ let bypassIndex = - 1 ;
227+ for ( let i = 0 ; i < this . _bypassSubscribers . length ; i ++ ) {
228+ if ( this . _bypassSubscribers [ i ] . handler === subscription ) {
229+ bypassIndex = i ;
230+ break ;
231+ }
232+ }
233+ if ( bypassIndex !== - 1 ) {
234+ const before = ArrayPrototypeSlice ( this . _bypassSubscribers , 0 , bypassIndex ) ;
235+ const after = ArrayPrototypeSlice ( this . _bypassSubscribers , bypassIndex + 1 ) ;
236+ this . _bypassSubscribers = before ;
237+ ArrayPrototypePushApply ( this . _bypassSubscribers , after ) ;
238+ if ( this . _bypassSubscribers . length === 0 ) {
239+ this . _bypassSubscribers = null ;
240+ }
241+ channels . decRef ( this . name ) ;
242+ if ( this . _index !== undefined ) subscriberCounts [ this . _index ] -- ;
243+ maybeMarkInactive ( this ) ;
244+ return true ;
245+ }
246+ }
186247
187- return true ;
248+ return false ;
188249 }
189250
190251 bindStore ( store , transform , options = { } ) {
191- const subscriberId = options && options . subscriberId !== undefined ? options . subscriberId : null ;
192- if ( subscriberId !== null ) {
193- const t = typeof subscriberId ;
194- if ( t === 'string' || t === 'number' || t === 'bigint' || t === 'boolean' ) {
195- throw new ERR_INVALID_ARG_TYPE ( 'subscriberId' , [ 'object' , 'symbol' , 'function' ] , subscriberId ) ;
196- }
197- }
252+ const subscriberId = options ?. subscriberId ;
198253
199- const replacing = this . _stores . has ( store ) ;
200- if ( ! replacing ) {
201- channels . incRef ( this . name ) ;
202- if ( this . _index !== undefined ) subscriberCounts [ this . _index ] ++ ;
254+ if ( subscriberId !== undefined ) {
255+ validateBypassKey ( subscriberId , 'subscriberId' ) ;
256+ // Bypass path — lazy separate SafeMap
257+ if ( this . _bypassStores === null ) {
258+ this . _bypassStores = new SafeMap ( ) ;
259+ }
260+ const replacing = this . _bypassStores . has ( store ) ;
261+ if ( ! replacing ) {
262+ channels . incRef ( this . name ) ;
263+ if ( this . _index !== undefined ) subscriberCounts [ this . _index ] ++ ;
264+ }
265+ this . _bypassStores . set ( store , { transform, subscriberId } ) ;
266+ } else {
267+ // Normal path — plain transform, zero extra cost
268+ const replacing = this . _stores . has ( store ) ;
269+ if ( ! replacing ) {
270+ channels . incRef ( this . name ) ;
271+ if ( this . _index !== undefined ) subscriberCounts [ this . _index ] ++ ;
272+ }
273+ this . _stores . set ( store , transform ) ;
203274 }
204- this . _stores . set ( store , { transform, subscriberId } ) ;
205275 }
206276
207277 unbindStore ( store ) {
208- if ( ! this . _stores . has ( store ) ) {
209- return false ;
278+ if ( this . _stores . has ( store ) ) {
279+ this . _stores . delete ( store ) ;
280+ channels . decRef ( this . name ) ;
281+ if ( this . _index !== undefined ) subscriberCounts [ this . _index ] -- ;
282+ maybeMarkInactive ( this ) ;
283+ return true ;
210284 }
211285
212- this . _stores . delete ( store ) ;
213-
214- channels . decRef ( this . name ) ;
215- if ( this . _index !== undefined ) subscriberCounts [ this . _index ] -- ;
216- maybeMarkInactive ( this ) ;
286+ if ( this . _bypassStores ?. has ( store ) ) {
287+ this . _bypassStores . delete ( store ) ;
288+ if ( this . _bypassStores . size === 0 ) {
289+ this . _bypassStores = null ;
290+ }
291+ channels . decRef ( this . name ) ;
292+ if ( this . _index !== undefined ) subscriberCounts [ this . _index ] -- ;
293+ maybeMarkInactive ( this ) ;
294+ return true ;
295+ }
217296
218- return true ;
297+ return false ;
219298 }
220299
221300 get hasSubscribers ( ) {
222301 return true ;
223302 }
224303
225304 publish ( data ) {
305+ // Normal path — no ALS lookup, plain function call, zero overhead
226306 const subscribers = this . _subscribers ;
227- const activeKeys = getSuppressionsStorage ( ) . getStore ( ) ;
228- for ( let i = 0 ; i < ( subscribers ?. length || 0 ) ; i ++ ) {
307+ for ( let i = 0 ; i < subscribers . length ; i ++ ) {
229308 try {
230- const { handler, subscriberId = null } = subscribers [ i ] ;
231- if ( subscriberId !== null && activeKeys ?. has ( subscriberId ) ) {
232- continue ;
233- }
234- handler ( data , this . name ) ;
309+ subscribers [ i ] ( data , this . name ) ;
235310 } catch ( err ) {
236311 process . nextTick ( ( ) => {
237312 triggerUncaughtException ( err , false ) ;
238313 } ) ;
239314 }
240315 }
316+
317+ // Bypass path — only entered if bypass subscribers exist
318+ if ( this . _bypassSubscribers !== null ) {
319+ const activeKeys = getSuppressionsStorage ( ) . getStore ( ) ;
320+ const bypassSubscribers = this . _bypassSubscribers ;
321+ for ( let i = 0 ; i < bypassSubscribers . length ; i ++ ) {
322+ try {
323+ const { handler, subscriberId } = bypassSubscribers [ i ] ;
324+ if ( activeKeys ?. has ( subscriberId ) ) continue ;
325+ handler ( data , this . name ) ;
326+ } catch ( err ) {
327+ process . nextTick ( ( ) => {
328+ triggerUncaughtException ( err , false ) ;
329+ } ) ;
330+ }
331+ }
332+ }
241333 }
242334
243335 withStoreScope ( data ) {
@@ -684,13 +776,7 @@ dc_binding.linkNativeChannel((name) => channel(name));
684776function suppressed ( key , fn , thisArg , ...args ) {
685777 validateFunction ( fn , 'fn' ) ;
686778
687- if ( key === null || key === undefined ) {
688- throw new ERR_INVALID_ARG_TYPE ( 'key' , [ 'object' , 'symbol' , 'function' ] , key ) ;
689- }
690- const t = typeof key ;
691- if ( t === 'string' || t === 'number' || t === 'bigint' || t === 'boolean' ) {
692- throw new ERR_INVALID_ARG_TYPE ( 'key' , [ 'object' , 'symbol' , 'function' ] , key ) ;
693- }
779+ validateBypassKey ( key , 'key' ) ;
694780
695781 const currentSet = getSuppressionsStorage ( ) . getStore ( ) ;
696782 const next = currentSet ? new SafeSet ( currentSet ) : new SafeSet ( ) ;
0 commit comments