@@ -42,6 +42,10 @@ interface ListenerEntry {
4242 once ?: true ;
4343}
4444
45+ interface ListEntryMap {
46+ [ eventName : string ] : Array < ListenerEntry > ;
47+ }
48+
4549let _wrappedIndex = 0 ;
4650
4751/**
@@ -107,7 +111,7 @@ export class Observable {
107111 */
108112 public _isViewBase : boolean ;
109113
110- private readonly _observers : { [ eventName : string ] : Array < ListenerEntry > } = { } ;
114+ private readonly _observers : ListEntryMap = { } ;
111115
112116 /**
113117 * Gets the value of the specified property.
@@ -379,7 +383,7 @@ export class Observable {
379383 const eventName = data . eventName + eventType ;
380384 const entries = _globalEventHandlers [ eventClass ] [ eventName ] ;
381385 if ( entries ) {
382- Observable . _handleEvent ( entries , data ) ;
386+ Observable . _fireEvent ( entries , data ) ;
383387 }
384388 }
385389
@@ -388,7 +392,7 @@ export class Observable {
388392 const eventName = data . eventName + eventType ;
389393 const entries = _globalEventHandlers [ '*' ] [ eventName ] ;
390394 if ( entries ) {
391- Observable . _handleEvent ( entries , data ) ;
395+ Observable . _fireEvent ( entries , data ) ;
392396 }
393397 }
394398 }
@@ -411,35 +415,49 @@ export class Observable {
411415
412416 const observers = this . _observers [ data . eventName ] ;
413417 if ( observers ) {
414- Observable . _handleEvent ( observers , dataWithObject ) ;
418+ Observable . _fireEvent ( observers , dataWithObject ) ;
415419 }
416420
417421 this . _globalNotify ( eventClass , '' , dataWithObject ) ;
418422 }
419423
420- private static _handleEvent < T extends EventData > ( observers : Array < ListenerEntry > , data : T ) : void {
421- if ( ! observers . length ) {
424+ private static _fireEvent < T extends EventData > ( observers : Array < ListenerEntry > , data : T ) : void {
425+ const length = observers . length ;
426+
427+ if ( ! length ) {
422428 return ;
423429 }
424430
425- for ( let i = observers . length - 1 ; i >= 0 ; i -- ) {
426- const entry = observers [ i ] ;
427- if ( ! entry ) {
428- continue ;
429- }
431+ if ( length === 1 ) {
432+ const index = 0 ;
433+ this . _handleListenerEntry < T > ( observers [ index ] , index , observers , data ) ;
434+ } else {
435+ // This keeps a copy of observers list to ensure concurrency
436+ const observersCp = observers . slice ( ) ;
430437
431- if ( entry . once ) {
432- observers . splice ( i , 1 ) ;
438+ for ( let i = 0 ; i < length ; i ++ ) {
439+ const entry = observersCp [ i ] ;
440+ this . _handleListenerEntry < T > ( entry , i , observers , data ) ;
433441 }
442+ }
443+ }
434444
435- const returnValue = entry . thisArg ? entry . callback . apply ( entry . thisArg , [ data ] ) : entry . callback ( data ) ;
445+ private static _handleListenerEntry < T extends EventData > ( entry : ListenerEntry , index : number , observers : Array < ListenerEntry > , data : T ) : void {
446+ if ( ! entry ) {
447+ return ;
448+ }
436449
437- // This ensures errors thrown inside asynchronous functions do not get swallowed
438- if ( returnValue instanceof Promise ) {
439- returnValue . catch ( ( err ) => {
440- console . error ( err ) ;
441- } ) ;
442- }
450+ if ( entry . once ) {
451+ observers . splice ( index , 1 ) ;
452+ }
453+
454+ const returnValue = entry . thisArg ? entry . callback . apply ( entry . thisArg , [ data ] ) : entry . callback ( data ) ;
455+
456+ // This ensures errors thrown inside asynchronous functions do not get swallowed
457+ if ( returnValue instanceof Promise ) {
458+ returnValue . catch ( ( err ) => {
459+ console . error ( err ) ;
460+ } ) ;
443461 }
444462 }
445463
0 commit comments