@@ -1003,6 +1003,9 @@ const PromiseState = {
1003
1003
*/
1004
1004
const ON_CANCEL_HANDLER = new WeakMap ;
1005
1005
1006
+ const SKIP_LOG = Symbol ( 'skip-log' ) ;
1007
+ const FLOW_LOG = logging . getLogger ( 'promise.ControlFlow' ) ;
1008
+
1006
1009
1007
1010
/**
1008
1011
* Represents the eventual value of a completed operation. Each promise may be
@@ -1025,14 +1028,29 @@ class ManagedPromise {
1025
1028
* functions, one for fulfilling the promise and another for rejecting it.
1026
1029
* @param {ControlFlow= } opt_flow The control flow
1027
1030
* this instance was created under. Defaults to the currently active flow.
1031
+ * @param {?= } opt_skipLog An internal parameter used to skip logging the
1032
+ * creation of this promise. This parameter has no effect unless it is
1033
+ * strictly equal to an internal symbol. In other words, this parameter
1034
+ * is always ignored for external code.
1028
1035
*/
1029
- constructor ( resolver , opt_flow ) {
1036
+ constructor ( resolver , opt_flow , opt_skipLog ) {
1030
1037
if ( ! usePromiseManager ( ) ) {
1031
1038
throw TypeError (
1032
1039
'Unable to create a managed promise instance: the promise manager has'
1033
1040
+ ' been disabled by the SELENIUM_PROMISE_MANAGER environment'
1034
1041
+ ' variable: ' + process . env [ 'SELENIUM_PROMISE_MANAGER' ] ) ;
1042
+ } else if ( opt_skipLog !== SKIP_LOG ) {
1043
+ FLOW_LOG . warning ( ( ) => {
1044
+ let e =
1045
+ captureStackTrace (
1046
+ 'ManagedPromiseError' ,
1047
+ 'Creating a new managed Promise. This call will fail when the'
1048
+ + ' promise manager is disabled' ,
1049
+ ManagedPromise )
1050
+ return e . stack ;
1051
+ } ) ;
1035
1052
}
1053
+
1036
1054
getUid ( this ) ;
1037
1055
1038
1056
/** @private {!ControlFlow} */
@@ -1432,15 +1450,19 @@ class Deferred {
1432
1450
/**
1433
1451
* @param {ControlFlow= } opt_flow The control flow this instance was
1434
1452
* created under. This should only be provided during unit tests.
1453
+ * @param {?= } opt_skipLog An internal parameter used to skip logging the
1454
+ * creation of this promise. This parameter has no effect unless it is
1455
+ * strictly equal to an internal symbol. In other words, this parameter
1456
+ * is always ignored for external code.
1435
1457
*/
1436
- constructor ( opt_flow ) {
1458
+ constructor ( opt_flow , opt_skipLog ) {
1437
1459
var fulfill , reject ;
1438
1460
1439
1461
/** @type {!ManagedPromise<T> } */
1440
1462
this . promise = new ManagedPromise ( function ( f , r ) {
1441
1463
fulfill = f ;
1442
1464
reject = r ;
1443
- } , opt_flow ) ;
1465
+ } , opt_flow , opt_skipLog ) ;
1444
1466
1445
1467
var self = this ;
1446
1468
var checkNotSelf = function ( value ) {
@@ -1563,9 +1585,17 @@ function defer() {
1563
1585
function fulfilled ( opt_value ) {
1564
1586
let ctor = usePromiseManager ( ) ? ManagedPromise : NativePromise ;
1565
1587
if ( opt_value instanceof ctor ) {
1566
- return /** @type {!Thenable<T> } */ ( opt_value ) ;
1588
+ return /** @type {!Thenable } */ ( opt_value ) ;
1589
+ }
1590
+
1591
+ if ( usePromiseManager ( ) ) {
1592
+ // We can skip logging warnings about creating a managed promise because
1593
+ // this function will automatically switch to use a native promise when
1594
+ // the promise manager is disabled.
1595
+ return new ManagedPromise (
1596
+ resolve => resolve ( opt_value ) , undefined , SKIP_LOG ) ;
1567
1597
}
1568
- return ctor . resolve ( opt_value ) ;
1598
+ return NativePromise . resolve ( opt_value ) ;
1569
1599
}
1570
1600
1571
1601
@@ -1582,7 +1612,11 @@ function fulfilled(opt_value) {
1582
1612
*/
1583
1613
function rejected ( opt_reason ) {
1584
1614
if ( usePromiseManager ( ) ) {
1585
- return ManagedPromise . reject ( opt_reason ) ;
1615
+ // We can skip logging warnings about creating a managed promise because
1616
+ // this function will automatically switch to use a native promise when
1617
+ // the promise manager is disabled.
1618
+ return new ManagedPromise (
1619
+ ( _ , reject ) => reject ( opt_reason ) , undefined , SKIP_LOG ) ;
1586
1620
}
1587
1621
return NativePromise . reject ( opt_reason ) ;
1588
1622
}
@@ -2444,23 +2478,39 @@ class ControlFlow extends events.EventEmitter {
2444
2478
}
2445
2479
2446
2480
if ( ! this . hold_ ) {
2447
- var holdIntervalMs = 2147483647 ; // 2^31-1; max timer length for Node.js
2481
+ let holdIntervalMs = 2147483647 ; // 2^31-1; max timer length for Node.js
2448
2482
this . hold_ = setInterval ( function ( ) { } , holdIntervalMs ) ;
2449
2483
}
2450
2484
2451
- var task = new Task (
2485
+ let task = new Task (
2452
2486
this , fn , opt_description || '<anonymous>' ,
2453
- { name : 'Task' , top : ControlFlow . prototype . execute } ) ;
2487
+ { name : 'Task' , top : ControlFlow . prototype . execute } ,
2488
+ true ) ;
2489
+
2490
+ let q = this . getActiveQueue_ ( ) ;
2491
+
2492
+ for ( let i = q . tasks_ . length ; i > 0 ; i -- ) {
2493
+ let previousTask = q . tasks_ [ i - 1 ] ;
2494
+ if ( previousTask . userTask_ ) {
2495
+ FLOW_LOG . warning ( ( ) => {
2496
+ return `Detected scheduling of an unchained task.
2497
+ When the promise manager is disabled, unchained tasks will not wait for
2498
+ previously scheduled tasks to finish before starting to execute.
2499
+ New task: ${ task . promise . stack_ . stack }
2500
+ Previous task: ${ previousTask . promise . stack_ . stack } ` . split ( / \n / ) . join ( '\n ' ) ;
2501
+ } ) ;
2502
+ break ;
2503
+ }
2504
+ }
2454
2505
2455
- var q = this . getActiveQueue_ ( ) ;
2456
2506
q . enqueue ( task ) ;
2457
2507
this . emit ( ControlFlow . EventType . SCHEDULE_TASK , task . description ) ;
2458
2508
return task . promise ;
2459
2509
}
2460
2510
2461
2511
/** @override */
2462
2512
promise ( resolver ) {
2463
- return new ManagedPromise ( resolver , this ) ;
2513
+ return new ManagedPromise ( resolver , this , SKIP_LOG ) ;
2464
2514
}
2465
2515
2466
2516
/** @override */
@@ -2729,9 +2779,11 @@ class Task extends Deferred {
2729
2779
* @param {string } description A description of the task for debugging.
2730
2780
* @param {{name: string, top: !Function}= } opt_stackOptions Options to use
2731
2781
* when capturing the stacktrace for when this task was created.
2782
+ * @param {boolean= } opt_isUserTask Whether this task was explicitly scheduled
2783
+ * by the use of the promise manager.
2732
2784
*/
2733
- constructor ( flow , fn , description , opt_stackOptions ) {
2734
- super ( flow ) ;
2785
+ constructor ( flow , fn , description , opt_stackOptions , opt_isUserTask ) {
2786
+ super ( flow , SKIP_LOG ) ;
2735
2787
getUid ( this ) ;
2736
2788
2737
2789
/** @type {function(): (T|!ManagedPromise<T>) } */
@@ -2743,6 +2795,9 @@ class Task extends Deferred {
2743
2795
/** @type {TaskQueue } */
2744
2796
this . queue = null ;
2745
2797
2798
+ /** @private @const {boolean} */
2799
+ this . userTask_ = ! ! opt_isUserTask ;
2800
+
2746
2801
/**
2747
2802
* Whether this task is considered block. A blocked task may be registered
2748
2803
* in a task queue, but will be dropped if it is still blocked when it
0 commit comments