@@ -45,6 +45,11 @@ export interface PatchEventTargetOptions {
4545export function patchEventTarget (
4646 api : _ZonePrivate , _global : any , apis : any [ ] , patchOptions ?: PatchEventTargetOptions ) {
4747 const invokeTask = function ( task : any , target : any , event : Event ) {
48+ // for better performance, check isRemoved which is set
49+ // by removeEventListener
50+ if ( task . isRemoved ) {
51+ return ;
52+ }
4853 const delegate = task . callback ;
4954 if ( typeof delegate === OBJECT_TYPE && delegate . handleEvent ) {
5055 // create the bind version of handleEvnet when invoke
@@ -62,8 +67,16 @@ export function patchEventTarget(
6267 const tasks = target [ zoneSymbolEventNames [ event . type ] [ FALSE_STR ] ] ;
6368 if ( tasks ) {
6469 // invoke all tasks which attached to current target with given event.type and capture = false
65- for ( let i = 0 ; i < tasks . length ; i ++ ) {
66- invokeTask ( tasks [ i ] , target , event ) ;
70+ if ( tasks . length === 1 ) {
71+ invokeTask ( tasks [ 0 ] , target , event ) ;
72+ } else {
73+ // https://github.com/angular/zone.js/issues/836
74+ // copy the tasks array before invoke, to avoid
75+ // the callback will remove itself or other listener
76+ const copyTasks = tasks . slice ( ) ;
77+ for ( let i = 0 ; i < copyTasks . length ; i ++ ) {
78+ invokeTask ( copyTasks [ i ] , target , event ) ;
79+ }
6780 }
6881 }
6982 } ;
@@ -74,8 +87,17 @@ export function patchEventTarget(
7487
7588 const tasks = target [ zoneSymbolEventNames [ event . type ] [ TRUE_STR ] ] ;
7689 if ( tasks ) {
77- for ( let i = 0 ; i < tasks . length ; i ++ ) {
78- invokeTask ( tasks [ i ] , target , event ) ;
90+ // invoke all tasks which attached to current target with given event.type and capture = false
91+ if ( tasks . length === 1 ) {
92+ invokeTask ( tasks [ 0 ] , target , event ) ;
93+ } else {
94+ // https://github.com/angular/zone.js/issues/836
95+ // copy the tasks array before invoke, to avoid
96+ // the callback will remove itself or other listener
97+ const copyTasks = tasks . slice ( ) ;
98+ for ( let i = 0 ; i < copyTasks . length ; i ++ ) {
99+ invokeTask ( copyTasks [ i ] , target , event ) ;
100+ }
79101 }
80102 }
81103 } ;
@@ -169,7 +191,7 @@ export function patchEventTarget(
169191 // if all tasks for the eventName + capture have gone,
170192 // we will really remove the global event callback,
171193 // if not, return
172- if ( ! task . remove ) {
194+ if ( ! task . allRemoved ) {
173195 return ;
174196 }
175197 return nativeRemoveEventListener . apply ( task . target , [
@@ -372,10 +394,12 @@ export function patchEventTarget(
372394 const typeOfDelegate = typeof delegate ;
373395 if ( compare ( existingTask , delegate ) ) {
374396 existingTasks . splice ( i , 1 ) ;
397+ // set isRemoved to data for faster invokeTask check
398+ ( existingTask as any ) . isRemoved = true ;
375399 if ( existingTasks . length === 0 ) {
376400 // all tasks for the eventName + capture have gone,
377401 // remove globalZoneAwareCallback and remove the task cache from target
378- ( existingTask as any ) . remove = true ;
402+ ( existingTask as any ) . allRemoved = true ;
379403 target [ symbolEventName ] = null ;
380404 }
381405 existingTask . zone . cancelTask ( existingTask ) ;
0 commit comments