@@ -61,6 +61,24 @@ goog.require('webdriver.stacktrace.Snapshot');
61
61
62
62
63
63
64
+ /**
65
+ * Error used when the computation of a promise is cancelled.
66
+ *
67
+ * @param {string= } opt_msg The cancellation message.
68
+ * @constructor
69
+ * @extends {goog.debug.Error }
70
+ * @final
71
+ */
72
+ webdriver . promise . CancellationError = function ( opt_msg ) {
73
+ goog . debug . Error . call ( this , opt_msg ) ;
74
+
75
+ /** @override */
76
+ this . name = 'CancellationError' ;
77
+ } ;
78
+ goog . inherits ( webdriver . promise . CancellationError , goog . debug . Error ) ;
79
+
80
+
81
+
64
82
/**
65
83
* Thenable is a promise-like object with a {@code then} method which may be
66
84
* used to schedule callbacks on a promised value.
@@ -75,9 +93,7 @@ webdriver.promise.Thenable = function() {};
75
93
* Cancels the computation of this promise's value, rejecting the promise in the
76
94
* process. This method is a no-op if the promise has alreayd been resolved.
77
95
*
78
- * @param {*= } opt_reason The reason this promise is being cancelled. If not an
79
- * {@code Error}, one will be created using the value's string
80
- * representation.
96
+ * @param {string= } opt_reason The reason this promise is being cancelled.
81
97
*/
82
98
webdriver . promise . Thenable . prototype . cancel = function ( opt_reason ) { } ;
83
99
@@ -297,16 +313,14 @@ webdriver.promise.Promise.prototype.thenFinally = function(callback) {
297
313
* the Deferred's canceller function (if provided). The canceller may return a
298
314
* truth-y value to override the reason provided for rejection.
299
315
*
300
- * @param {Function= } opt_canceller Function to call when cancelling the
301
- * computation of this instance's value.
302
316
* @param {webdriver.promise.ControlFlow= } opt_flow The control flow
303
317
* this instance was created under. This should only be provided during
304
318
* unit tests.
305
319
* @constructor
306
320
* @extends {webdriver.promise.Promise.<T> }
307
321
* @template T
308
322
*/
309
- webdriver . promise . Deferred = function ( opt_canceller , opt_flow ) {
323
+ webdriver . promise . Deferred = function ( opt_flow ) {
310
324
/* NOTE: This class's implementation diverges from the prototypical style
311
325
* used in the rest of the atoms library. This was done intentionally to
312
326
* protect the internal Deferred state from consumers, as outlined by
@@ -316,6 +330,12 @@ webdriver.promise.Deferred = function(opt_canceller, opt_flow) {
316
330
317
331
var flow = opt_flow || webdriver . promise . controlFlow ( ) ;
318
332
333
+ /**
334
+ * The deferred this instance is chained from, if any.
335
+ * @private {webdriver.promise.Deferred.<?>}
336
+ */
337
+ this . parent_ = null ;
338
+
319
339
/**
320
340
* The listeners registered with this Deferred. Each element in the list will
321
341
* be a 3-tuple of the callback function, errback function, and the
@@ -422,7 +442,8 @@ webdriver.promise.Deferred = function(opt_canceller, opt_flow) {
422
442
notify ( listeners . shift ( ) ) ;
423
443
}
424
444
425
- if ( ! handled && state == webdriver . promise . Deferred . State_ . REJECTED ) {
445
+ if ( ! handled && state == webdriver . promise . Deferred . State_ . REJECTED &&
446
+ ! ( value instanceof webdriver . promise . CancellationError ) ) {
426
447
flow . pendingRejections_ += 1 ;
427
448
pendingRejectionKey = flow . timer . setTimeout ( function ( ) {
428
449
pendingRejectionKey = null ;
@@ -457,6 +478,8 @@ webdriver.promise.Deferred = function(opt_canceller, opt_flow) {
457
478
*/
458
479
var promise = new webdriver . promise . Promise ( ) ;
459
480
481
+ var self = this ;
482
+
460
483
/**
461
484
* Registers a callback on this Deferred.
462
485
*
@@ -482,7 +505,9 @@ webdriver.promise.Deferred = function(opt_canceller, opt_flow) {
482
505
pendingRejectionKey = null ;
483
506
}
484
507
485
- var deferred = new webdriver . promise . Deferred ( cancel , flow ) ;
508
+ var deferred = new webdriver . promise . Deferred ( flow ) ;
509
+ deferred . parent_ = self ;
510
+
486
511
var listener = {
487
512
callback : opt_callback ,
488
513
errback : opt_errback ,
@@ -500,8 +525,6 @@ webdriver.promise.Deferred = function(opt_canceller, opt_flow) {
500
525
return deferred . promise ;
501
526
}
502
527
503
- var self = this ;
504
-
505
528
/**
506
529
* Resolves this promise with the given value. If the value is itself a
507
530
* promise and not a reference to this deferred, this instance will wait for
@@ -525,18 +548,17 @@ webdriver.promise.Deferred = function(opt_canceller, opt_flow) {
525
548
/**
526
549
* Attempts to cancel the computation of this instance's value. This attempt
527
550
* will silently fail if this instance has already resolved.
528
- * @param {*= } opt_reason The reason for cancelling this promise.
529
- */
551
+ * @param {string= } opt_reason The reason for cancelling this promise. */
530
552
function cancel ( opt_reason ) {
531
553
if ( ! isPending ( ) ) {
532
554
return ;
533
555
}
534
556
535
- if ( opt_canceller ) {
536
- opt_reason = opt_canceller ( opt_reason ) || opt_reason ;
557
+ if ( self . parent_ ) {
558
+ self . parent_ . cancel ( opt_reason ) ;
559
+ } else {
560
+ reject ( new webdriver . promise . CancellationError ( opt_reason ) ) ;
537
561
}
538
-
539
- reject ( opt_reason ) ;
540
562
}
541
563
542
564
this . promise = promise ;
@@ -630,24 +652,22 @@ webdriver.promise.isPromise = function(value) {
630
652
*/
631
653
webdriver . promise . delayed = function ( ms ) {
632
654
var timer = webdriver . promise . controlFlow ( ) . timer ;
633
- var key ;
634
- var deferred = new webdriver . promise . Deferred ( function ( ) {
655
+ var deferred = new webdriver . promise . Deferred ( ) ;
656
+ var key = timer . setTimeout ( deferred . fulfill , ms ) ;
657
+ return deferred . thenCatch ( function ( e ) {
635
658
timer . clearTimeout ( key ) ;
659
+ throw e ;
636
660
} ) ;
637
- key = timer . setTimeout ( deferred . fulfill , ms ) ;
638
- return deferred . promise ;
639
661
} ;
640
662
641
663
642
664
/**
643
665
* Creates a new deferred object.
644
- * @param {Function= } opt_canceller Function to call when cancelling the
645
- * computation of this instance's value.
646
666
* @return {!webdriver.promise.Deferred.<T> } The new deferred object.
647
667
* @template T
648
668
*/
649
- webdriver . promise . defer = function ( opt_canceller ) {
650
- return new webdriver . promise . Deferred ( opt_canceller ) ;
669
+ webdriver . promise . defer = function ( ) {
670
+ return new webdriver . promise . Deferred ( ) ;
651
671
} ;
652
672
653
673
@@ -694,9 +714,7 @@ webdriver.promise.rejected = function(opt_reason) {
694
714
* result of the provided function's callback.
695
715
*/
696
716
webdriver . promise . checkedNodeCall = function ( fn , var_args ) {
697
- var deferred = new webdriver . promise . Deferred ( function ( ) {
698
- throw Error ( 'This Deferred may not be cancelled' ) ;
699
- } ) ;
717
+ var deferred = new webdriver . promise . Deferred ( ) ;
700
718
try {
701
719
var args = goog . array . slice ( arguments , 1 ) ;
702
720
args . push ( function ( error , value ) {
@@ -1661,13 +1679,12 @@ webdriver.promise.ControlFlow.prototype.runInNewFrame_ = function(
1661
1679
errback ( e ) ;
1662
1680
} ;
1663
1681
} catch ( ex ) {
1664
- removeNewFrame ( new webdriver . promise . CanceledTaskError_ ( ex ) ) ;
1682
+ removeNewFrame ( ex ) ;
1665
1683
errback ( ex ) ;
1666
1684
}
1667
1685
1668
1686
/**
1669
- * @param {webdriver.promise.CanceledTaskError_= } opt_err If provided, the
1670
- * error that triggered the removal of this frame.
1687
+ * @param {*= } opt_err If provided, the reason that the frame was removed.
1671
1688
*/
1672
1689
function removeNewFrame ( opt_err ) {
1673
1690
var parent = newFrame . getParent ( ) ;
@@ -1676,7 +1693,8 @@ webdriver.promise.ControlFlow.prototype.runInNewFrame_ = function(
1676
1693
}
1677
1694
1678
1695
if ( opt_err ) {
1679
- newFrame . cancelRemainingTasks ( opt_err ) ;
1696
+ newFrame . cancelRemainingTasks (
1697
+ 'Tasks cancelled due to uncaught error: ' + opt_err ) ;
1680
1698
}
1681
1699
self . activeFrame_ = oldFrame ;
1682
1700
}
@@ -1858,7 +1876,8 @@ webdriver.promise.Frame_.prototype.getRoot = function() {
1858
1876
* @param {* } error The error that triggered this abortion.
1859
1877
*/
1860
1878
webdriver . promise . Frame_ . prototype . abort = function ( error ) {
1861
- this . cancelRemainingTasks ( new webdriver . promise . CanceledTaskError_ ( error ) ) ;
1879
+ this . cancelRemainingTasks (
1880
+ 'Task discarded due to a previous task failure: ' + error ) ;
1862
1881
1863
1882
var frame = this ;
1864
1883
frame . flow_ . pendingRejections_ += 1 ;
@@ -1915,23 +1934,22 @@ webdriver.promise.Frame_.prototype.notify_ = function(fn, opt_error) {
1915
1934
* });
1916
1935
* });
1917
1936
* // flow failed: Error: boom
1918
- * // task failed! CanceledTaskError : Task discarded due to a previous
1937
+ * // task failed! CancelledTaskError : Task discarded due to a previous
1919
1938
* // task failure: Error: boom
1920
1939
*
1921
- * @param {!webdriver.promise.CanceledTaskError_ } error The cancellation
1922
- * error.
1940
+ * @param {string } reason The cancellation reason.
1923
1941
*/
1924
- webdriver . promise . Frame_ . prototype . cancelRemainingTasks = function ( error ) {
1942
+ webdriver . promise . Frame_ . prototype . cancelRemainingTasks = function ( reason ) {
1925
1943
goog . array . forEach ( this . children_ , function ( child ) {
1926
1944
if ( child instanceof webdriver . promise . Frame_ ) {
1927
- child . cancelRemainingTasks ( error ) ;
1945
+ child . cancelRemainingTasks ( reason ) ;
1928
1946
} else {
1929
1947
// None of the previously registered listeners should be notified that
1930
1948
// the task is being canceled, however, we need at least one errback
1931
1949
// to prevent the cancellation from bubbling up.
1932
1950
child . removeAll ( ) ;
1933
1951
child . thenCatch ( goog . nullFunction ) ;
1934
- child . cancel ( error ) ;
1952
+ child . cancel ( reason ) ;
1935
1953
}
1936
1954
} ) ;
1937
1955
} ;
@@ -2043,7 +2061,7 @@ webdriver.promise.Frame_.prototype.toString = function() {
2043
2061
* @private
2044
2062
*/
2045
2063
webdriver . promise . Task_ = function ( flow , fn , description , snapshot ) {
2046
- webdriver . promise . Deferred . call ( this , null , flow ) ;
2064
+ webdriver . promise . Deferred . call ( this , flow ) ;
2047
2065
2048
2066
/**
2049
2067
* @type {function(): (T|!webdriver.promise.Promise.<T>) }
@@ -2080,25 +2098,6 @@ webdriver.promise.Task_.prototype.toString = function() {
2080
2098
2081
2099
2082
2100
2083
- /**
2084
- * Special error used to signal when a task is canceled because a previous
2085
- * task in the same frame failed.
2086
- * @param {* } err The error that caused the task cancellation.
2087
- * @constructor
2088
- * @extends {goog.debug.Error }
2089
- * @private
2090
- */
2091
- webdriver . promise . CanceledTaskError_ = function ( err ) {
2092
- goog . base ( this , 'Task discarded due to a previous task failure: ' + err ) ;
2093
- } ;
2094
- goog . inherits ( webdriver . promise . CanceledTaskError_ , goog . debug . Error ) ;
2095
-
2096
-
2097
- /** @override */
2098
- webdriver . promise . CanceledTaskError_ . prototype . name = 'CanceledTaskError' ;
2099
-
2100
-
2101
-
2102
2101
/**
2103
2102
* The default flow to use if no others are active.
2104
2103
* @private {!webdriver.promise.ControlFlow}
0 commit comments