@@ -514,17 +514,58 @@ Timeout.prototype.close = function() {
514
514
} ;
515
515
516
516
517
- var immediateQueue = L . create ( ) ;
517
+ // A linked list for storing `setImmediate()` requests
518
+ function ImmediateList ( ) {
519
+ this . head = null ;
520
+ this . tail = null ;
521
+ }
522
+
523
+ // Appends an item to the end of the linked list, adjusting the current tail's
524
+ // previous and next pointers where applicable
525
+ ImmediateList . prototype . append = function ( item ) {
526
+ if ( this . tail ) {
527
+ this . tail . _idleNext = item ;
528
+ item . _idlePrev = this . tail ;
529
+ } else {
530
+ this . head = item ;
531
+ }
532
+ this . tail = item ;
533
+ } ;
534
+
535
+ // Removes an item from the linked list, adjusting the pointers of adjacent
536
+ // items and the linked list's head or tail pointers as necessary
537
+ ImmediateList . prototype . remove = function ( item ) {
538
+ if ( item . _idleNext ) {
539
+ item . _idleNext . _idlePrev = item . _idlePrev ;
540
+ }
541
+
542
+ if ( item . _idlePrev ) {
543
+ item . _idlePrev . _idleNext = item . _idleNext ;
544
+ }
545
+
546
+ if ( item === this . head )
547
+ this . head = item . _idleNext ;
548
+ if ( item === this . tail )
549
+ this . tail = item . _idlePrev ;
550
+
551
+ item . _idleNext = null ;
552
+ item . _idlePrev = null ;
553
+ } ;
554
+
555
+ // Create a single linked list instance only once at startup
556
+ var immediateQueue = new ImmediateList ( ) ;
518
557
519
558
520
559
function processImmediate ( ) {
521
- const queue = immediateQueue ;
522
- var domain , immediate ;
560
+ var immediate = immediateQueue . head ;
561
+ var tail = immediateQueue . tail ;
562
+ var domain ;
523
563
524
- immediateQueue = L . create ( ) ;
564
+ // Clear the linked list early in case new `setImmediate()` calls occur while
565
+ // immediate callbacks are executed
566
+ immediateQueue . head = immediateQueue . tail = null ;
525
567
526
- while ( L . isEmpty ( queue ) === false ) {
527
- immediate = L . shift ( queue ) ;
568
+ while ( immediate ) {
528
569
domain = immediate . domain ;
529
570
530
571
if ( ! immediate . _onImmediate )
@@ -534,36 +575,45 @@ function processImmediate() {
534
575
domain . enter ( ) ;
535
576
536
577
immediate . _callback = immediate . _onImmediate ;
537
- tryOnImmediate ( immediate , queue ) ;
578
+ tryOnImmediate ( immediate , tail ) ;
538
579
539
580
if ( domain )
540
581
domain . exit ( ) ;
582
+
583
+ immediate = immediate . _idleNext ;
541
584
}
542
585
543
586
// Only round-trip to C++ land if we have to. Calling clearImmediate() on an
544
587
// immediate that's in |queue| is okay. Worst case is we make a superfluous
545
588
// call to NeedImmediateCallbackSetter().
546
- if ( L . isEmpty ( immediateQueue ) ) {
589
+ if ( ! immediateQueue . head ) {
547
590
process . _needImmediateCallback = false ;
548
591
}
549
592
}
550
593
551
594
552
595
// An optimization so that the try/finally only de-optimizes (since at least v8
553
596
// 4.7) what is in this smaller function.
554
- function tryOnImmediate ( immediate , queue ) {
597
+ function tryOnImmediate ( immediate , oldTail ) {
555
598
var threw = true ;
556
599
try {
557
600
// make the actual call outside the try/catch to allow it to be optimized
558
601
runCallback ( immediate ) ;
559
602
threw = false ;
560
603
} finally {
561
- if ( threw && ! L . isEmpty ( queue ) ) {
604
+ if ( threw && immediate . _idleNext ) {
562
605
// Handle any remaining on next tick, assuming we're still alive to do so.
563
- while ( ! L . isEmpty ( immediateQueue ) ) {
564
- L . append ( queue , L . shift ( immediateQueue ) ) ;
606
+ const curHead = immediateQueue . head ;
607
+ const next = immediate . _idleNext ;
608
+ if ( curHead ) {
609
+ curHead . _idlePrev = oldTail ;
610
+ oldTail . _idleNext = curHead ;
611
+ next . _idlePrev = null ;
612
+ immediateQueue . head = next ;
613
+ } else {
614
+ immediateQueue . head = next ;
615
+ immediateQueue . tail = oldTail ;
565
616
}
566
- immediateQueue = queue ;
567
617
process . nextTick ( processImmediate ) ;
568
618
}
569
619
}
@@ -617,17 +667,17 @@ exports.setImmediate = function(callback, arg1, arg2, arg3) {
617
667
case 3 :
618
668
args = [ arg1 , arg2 ] ;
619
669
break ;
620
- case 4 :
621
- args = [ arg1 , arg2 , arg3 ] ;
622
- break ;
623
- // slow case
624
670
default :
625
671
args = [ arg1 , arg2 , arg3 ] ;
626
672
for ( i = 4 ; i < arguments . length ; i ++ )
627
673
// extend array dynamically, makes .apply run much faster in v6.0.0
628
674
args [ i - 1 ] = arguments [ i ] ;
629
675
break ;
630
676
}
677
+ return createImmediate ( args , callback ) ;
678
+ } ;
679
+
680
+ function createImmediate ( args , callback ) {
631
681
// declaring it `const immediate` causes v6.0.0 to deoptimize this function
632
682
var immediate = new Immediate ( ) ;
633
683
immediate . _callback = callback ;
@@ -639,20 +689,20 @@ exports.setImmediate = function(callback, arg1, arg2, arg3) {
639
689
process . _immediateCallback = processImmediate ;
640
690
}
641
691
642
- L . append ( immediateQueue , immediate ) ;
692
+ immediateQueue . append ( immediate ) ;
643
693
644
694
return immediate ;
645
- } ;
695
+ }
646
696
647
697
648
698
exports . clearImmediate = function ( immediate ) {
649
699
if ( ! immediate ) return ;
650
700
651
- immediate . _onImmediate = undefined ;
701
+ immediate . _onImmediate = null ;
652
702
653
- L . remove ( immediate ) ;
703
+ immediateQueue . remove ( immediate ) ;
654
704
655
- if ( L . isEmpty ( immediateQueue ) ) {
705
+ if ( ! immediateQueue . head ) {
656
706
process . _needImmediateCallback = false ;
657
707
}
658
708
} ;
0 commit comments