@@ -1271,14 +1271,13 @@ function $RootScopeProvider() {
1271
1271
1272
1272
var self = this ;
1273
1273
return function ( ) {
1274
- var index = arrayRemove ( namedListeners , listener ) ;
1275
- if ( index >= 0 ) {
1274
+ var indexOfListener = namedListeners . indexOf ( listener ) ;
1275
+ if ( indexOfListener !== - 1 ) {
1276
+ // Use delete in the hope of the browser deallocating the memory for the array entry,
1277
+ // while not shifting the array indexes of other listeners.
1278
+ // See issue https://github.com/angular/angular.js/issues/16135
1279
+ delete namedListeners [ indexOfListener ] ;
1276
1280
decrementListenerCount ( self , 1 , name ) ;
1277
- // We are removing a listener while iterating over the list of listeners.
1278
- // Update the current $$index if necessary to ensure no listener is skipped.
1279
- if ( index <= namedListeners . $$index ) {
1280
- namedListeners . $$index -- ;
1281
- }
1282
1281
}
1283
1282
} ;
1284
1283
} ,
@@ -1307,7 +1306,9 @@ function $RootScopeProvider() {
1307
1306
* @return {Object } Event object (see {@link ng.$rootScope.Scope#$on}).
1308
1307
*/
1309
1308
$emit : function ( name , args ) {
1310
- var scope = this ,
1309
+ var empty = [ ] ,
1310
+ namedListeners ,
1311
+ scope = this ,
1311
1312
stopPropagation = false ,
1312
1313
event = {
1313
1314
name : name ,
@@ -1318,11 +1319,28 @@ function $RootScopeProvider() {
1318
1319
} ,
1319
1320
defaultPrevented : false
1320
1321
} ,
1321
- listenerArgs = concat ( [ event ] , arguments , 1 ) ;
1322
+ listenerArgs = concat ( [ event ] , arguments , 1 ) ,
1323
+ i , length ;
1322
1324
1323
1325
do {
1324
- invokeListeners ( scope , event , listenerArgs , name ) ;
1325
-
1326
+ namedListeners = scope . $$listeners [ name ] || empty ;
1327
+ event . currentScope = scope ;
1328
+ for ( i = 0 , length = namedListeners . length ; i < length ; i ++ ) {
1329
+
1330
+ // if listeners were deregistered, defragment the array
1331
+ if ( ! namedListeners [ i ] ) {
1332
+ namedListeners . splice ( i , 1 ) ;
1333
+ i -- ;
1334
+ length -- ;
1335
+ continue ;
1336
+ }
1337
+ try {
1338
+ //allow all listeners attached to the current scope to run
1339
+ namedListeners [ i ] . apply ( null , listenerArgs ) ;
1340
+ } catch ( e ) {
1341
+ $exceptionHandler ( e ) ;
1342
+ }
1343
+ }
1326
1344
//if any listener on the current scope stops propagation, prevent bubbling
1327
1345
if ( stopPropagation ) {
1328
1346
break ;
@@ -1373,11 +1391,28 @@ function $RootScopeProvider() {
1373
1391
1374
1392
if ( ! target . $$listenerCount [ name ] ) return event ;
1375
1393
1376
- var listenerArgs = concat ( [ event ] , arguments , 1 ) ;
1394
+ var listenerArgs = concat ( [ event ] , arguments , 1 ) ,
1395
+ listeners , i , length ;
1377
1396
1378
1397
//down while you can, then up and next sibling or up and next sibling until back at root
1379
1398
while ( ( current = next ) ) {
1380
- invokeListeners ( current , event , listenerArgs , name ) ;
1399
+ event . currentScope = current ;
1400
+ listeners = current . $$listeners [ name ] || [ ] ;
1401
+ for ( i = 0 , length = listeners . length ; i < length ; i ++ ) {
1402
+ // if listeners were deregistered, defragment the array
1403
+ if ( ! listeners [ i ] ) {
1404
+ listeners . splice ( i , 1 ) ;
1405
+ i -- ;
1406
+ length -- ;
1407
+ continue ;
1408
+ }
1409
+
1410
+ try {
1411
+ listeners [ i ] . apply ( null , listenerArgs ) ;
1412
+ } catch ( e ) {
1413
+ $exceptionHandler ( e ) ;
1414
+ }
1415
+ }
1381
1416
1382
1417
// Insanity Warning: scope depth-first traversal
1383
1418
// yes, this code is a bit crazy, but it works and we have tests to prove it!
@@ -1408,27 +1443,6 @@ function $RootScopeProvider() {
1408
1443
1409
1444
return $rootScope ;
1410
1445
1411
- function invokeListeners ( scope , event , listenerArgs , name ) {
1412
- var listeners = scope . $$listeners [ name ] ;
1413
- if ( listeners ) {
1414
- if ( listeners . $$index !== undefined ) {
1415
- throw $rootScopeMinErr ( 'inevt' , '{0} already $emit/$broadcast-ing on scope ({1})' , name , scope . $id ) ;
1416
- }
1417
- event . currentScope = scope ;
1418
- try {
1419
- for ( listeners . $$index = 0 ; listeners . $$index < listeners . length ; listeners . $$index ++ ) {
1420
- try {
1421
- //allow all listeners attached to the current scope to run
1422
- listeners [ listeners . $$index ] . apply ( null , listenerArgs ) ;
1423
- } catch ( e ) {
1424
- $exceptionHandler ( e ) ;
1425
- }
1426
- }
1427
- } finally {
1428
- listeners . $$index = undefined ;
1429
- }
1430
- }
1431
- }
1432
1446
1433
1447
function beginPhase ( phase ) {
1434
1448
if ( $rootScope . $$phase ) {
0 commit comments