Index: src/promise.js |
diff --git a/src/promise.js b/src/promise.js |
index 37c10ec08eb298d5543738531168fe0315ca7854..e402a18532647b96b6b07268858f95c4aa627064 100644 |
--- a/src/promise.js |
+++ b/src/promise.js |
@@ -19,6 +19,7 @@ var PromiseChain; |
var PromiseCatch; |
var PromiseThen; |
var PromiseHasRejectHandler; |
+var PromiseHasUserDefinedRejectHandler; |
// mirror-debugger.js currently uses builtins.promiseStatus. It would be nice |
// if we could move these property names into the closure below. |
@@ -30,9 +31,10 @@ var promiseValue = GLOBAL_PRIVATE("Promise#value"); |
var promiseOnResolve = GLOBAL_PRIVATE("Promise#onResolve"); |
var promiseOnReject = GLOBAL_PRIVATE("Promise#onReject"); |
var promiseRaw = GLOBAL_PRIVATE("Promise#raw"); |
-var promiseDebug = GLOBAL_PRIVATE("Promise#debug"); |
+var promiseHasHandler = %PromiseHasHandlerSymbol(); |
var lastMicrotaskId = 0; |
+ |
(function() { |
var $Promise = function Promise(resolver) { |
@@ -159,11 +161,12 @@ var lastMicrotaskId = 0; |
PromiseReject = function PromiseReject(promise, r) { |
// Check promise status to confirm that this reject has an effect. |
- // Check promiseDebug property to avoid duplicate event. |
- if (DEBUG_IS_ACTIVE && |
- GET_PRIVATE(promise, promiseStatus) == 0 && |
- !HAS_DEFINED_PRIVATE(promise, promiseDebug)) { |
- %DebugPromiseRejectEvent(promise, r); |
+ // Call runtime for callbacks to the debugger or for unhandled reject. |
+ if (GET_PRIVATE(promise, promiseStatus) == 0) { |
+ var debug_is_active = DEBUG_IS_ACTIVE; |
+ if (debug_is_active || !HAS_DEFINED_PRIVATE(promise, promiseHasHandler)) { |
+ %PromiseRejectEvent(promise, r, debug_is_active); |
+ } |
} |
PromiseDone(promise, -1, r, promiseOnReject) |
} |
@@ -199,12 +202,17 @@ var lastMicrotaskId = 0; |
} |
function PromiseRejected(r) { |
+ var promise; |
if (this === $Promise) { |
// Optimized case, avoid extra closure. |
- return PromiseSet(new $Promise(promiseRaw), -1, r); |
+ promise = PromiseSet(new $Promise(promiseRaw), -1, r); |
+ // The debug event for this would always be an uncaught promise reject, |
+ // which is usually simply noise. Do not trigger that debug event. |
+ %PromiseRejectEvent(promise, r, false); |
} else { |
- return new this(function(resolve, reject) { reject(r) }); |
+ promise = new this(function(resolve, reject) { reject(r) }); |
} |
+ return promise; |
} |
// Simple chaining. |
@@ -227,11 +235,18 @@ var lastMicrotaskId = 0; |
+1); |
break; |
case -1: // Rejected |
+ if (!HAS_DEFINED_PRIVATE(this, promiseHasHandler)) { |
+ // Promise has already been rejected, but had no handler. |
+ // Revoke previously triggered reject event. |
+ %PromiseRevokeReject(this); |
+ } |
PromiseEnqueue(GET_PRIVATE(this, promiseValue), |
[onReject, deferred], |
-1); |
break; |
} |
+ // Mark this promise as having handler. |
+ SET_PRIVATE(this, promiseHasHandler, true); |
if (DEBUG_IS_ACTIVE) { |
%DebugPromiseEvent({ promise: deferred.promise, parentPromise: this }); |
} |
@@ -325,22 +340,24 @@ var lastMicrotaskId = 0; |
// Utility for debugger |
- function PromiseHasRejectHandlerRecursive(promise) { |
+ function PromiseHasUserDefinedRejectHandlerRecursive(promise) { |
var queue = GET_PRIVATE(promise, promiseOnReject); |
if (IS_UNDEFINED(queue)) return false; |
- // Do a depth first search for a reject handler that's not |
- // the default PromiseIdRejectHandler. |
for (var i = 0; i < queue.length; i += 2) { |
if (queue[i] != PromiseIdRejectHandler) return true; |
- if (PromiseHasRejectHandlerRecursive(queue[i + 1].promise)) return true; |
+ if (PromiseHasUserDefinedRejectHandlerRecursive(queue[i + 1].promise)) { |
+ return true; |
+ } |
} |
return false; |
} |
- PromiseHasRejectHandler = function PromiseHasRejectHandler() { |
- // Mark promise as already having triggered a reject event. |
- SET_PRIVATE(this, promiseDebug, true); |
- return PromiseHasRejectHandlerRecursive(this); |
+ // Return whether the promise will be handled by a user-defined reject |
+ // handler somewhere down the promise chain. For this, we do a depth-first |
+ // search for a reject handler that's not the default PromiseIdRejectHandler. |
+ PromiseHasUserDefinedRejectHandler = |
+ function PromiseHasUserDefinedRejectHandler() { |
+ return PromiseHasUserDefinedRejectHandlerRecursive(this); |
}; |
// ------------------------------------------------------------------- |