Chromium Code Reviews| Index: src/promise.js |
| diff --git a/src/promise.js b/src/promise.js |
| index 443a3b8c01a15d2d8cd4de98e4dfb10219fcb511..bae10fbc92bad2bcaec10fcccf4e9ca17d48b71a 100644 |
| --- a/src/promise.js |
| +++ b/src/promise.js |
| @@ -100,16 +100,30 @@ var lastMicrotaskId = 0; |
| return x; |
| } |
| - function PromiseHandle(value, handler, deferred) { |
| + function PromiseHandle(value, handler, deferred, thenable) { |
| try { |
| %DebugPushPromise(deferred.promise); |
| var result = handler(value); |
| - if (result === deferred.promise) |
| + if (result === deferred.promise) { |
| throw MakeTypeError('promise_cyclic', [result]); |
| - else if (IsPromise(result)) |
| + } else if (IsPromise(result) && thenable) { |
| + var then = result.then; |
|
arv (Not doing code reviews)
2015/05/11 13:53:15
Isn't this extra Get observable?
yhirano
2015/05/12 06:09:19
In PromiseReactionJob[1], promiseCapability.[[Reso
|
| + if (IS_SPEC_FUNCTION(then)) { |
| + %EnqueueMicrotask(function() { |
| + try { |
| + %_CallFunction(result, deferred.resolve, deferred.reject, then); |
| + } catch(exception) { |
| + try { deferred.reject(exception); } catch (e) { } |
|
caitp (gmail)
2015/05/11 03:02:16
Is this not already handled by the enclosing try/c
caitp (gmail)
2015/05/11 03:06:05
wait, I get it --- I guess it's not
arv (Not doing code reviews)
2015/05/11 13:53:15
I think it is :-)
Line 128
caitp (gmail)
2015/05/11 15:02:34
Yeah, but this one is in a closure passed to Enque
|
| + } |
| + }); |
| + } else { |
| + deferred.resolve(result); |
|
caitp (gmail)
2015/05/11 03:02:16
This same branch is repeated a few times, maybe it
yhirano
2015/05/12 06:09:19
Hmm, I don't have a good idea to unify them (parti
|
| + } |
| + } else if (IsPromise(result)) { |
| %_CallFunction(result, deferred.resolve, deferred.reject, PromiseChain); |
| - else |
| + } else { |
| deferred.resolve(result); |
| + } |
| } catch (exception) { |
| try { deferred.reject(exception); } catch (e) { } |
| } finally { |
| @@ -123,8 +137,8 @@ var lastMicrotaskId = 0; |
| if (instrumenting) { |
| %DebugAsyncTaskEvent({ type: "willHandle", id: id, name: name }); |
| } |
| - for (var i = 0; i < tasks.length; i += 2) { |
| - PromiseHandle(value, tasks[i], tasks[i + 1]) |
| + for (var i = 0; i < tasks.length; i += 3) { |
|
caitp (gmail)
2015/05/11 03:02:16
This gets confusing, comments would be helpful
yhirano
2015/05/12 06:09:19
Done.
|
| + PromiseHandle(value, tasks[i], tasks[i + 1], tasks[i + 2]) |
| } |
| if (instrumenting) { |
| %DebugAsyncTaskEvent({ type: "didHandle", id: id, name: name }); |
| @@ -137,6 +151,41 @@ var lastMicrotaskId = 0; |
| } |
| } |
| + function PromiseChainInternal(onResolve, onReject, thenable) { |
| + onResolve = IS_UNDEFINED(onResolve) ? PromiseIdResolveHandler : onResolve; |
| + onReject = IS_UNDEFINED(onReject) ? PromiseIdRejectHandler : onReject; |
| + var deferred = %_CallFunction(this.constructor, PromiseDeferred); |
| + switch (GET_PRIVATE(this, promiseStatus)) { |
| + case UNDEFINED: |
| + throw MakeTypeError('not_a_promise', [this]); |
| + case 0: // Pending |
| + GET_PRIVATE(this, promiseOnResolve).push(onResolve, deferred, thenable); |
| + GET_PRIVATE(this, promiseOnReject).push(onReject, deferred, thenable); |
| + break; |
| + case +1: // Resolved |
| + PromiseEnqueue(GET_PRIVATE(this, promiseValue), |
| + [onResolve, deferred, thenable], |
| + +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, thenable], |
| + -1); |
| + break; |
| + } |
| + // Mark this promise as having handler. |
| + SET_PRIVATE(this, promiseHasHandler, true); |
| + if (DEBUG_IS_ACTIVE) { |
| + %DebugPromiseEvent({ promise: deferred.promise, parentPromise: this }); |
| + } |
| + return deferred.promise; |
| + } |
| + |
| function PromiseIdResolveHandler(x) { return x } |
| function PromiseIdRejectHandler(r) { throw r } |
| @@ -219,38 +268,8 @@ var lastMicrotaskId = 0; |
| PromiseChain = function PromiseChain(onResolve, onReject) { // a.k.a. |
| // flatMap |
| - onResolve = IS_UNDEFINED(onResolve) ? PromiseIdResolveHandler : onResolve; |
| - onReject = IS_UNDEFINED(onReject) ? PromiseIdRejectHandler : onReject; |
| - var deferred = %_CallFunction(this.constructor, PromiseDeferred); |
| - switch (GET_PRIVATE(this, promiseStatus)) { |
| - case UNDEFINED: |
| - throw MakeTypeError('not_a_promise', [this]); |
| - case 0: // Pending |
| - GET_PRIVATE(this, promiseOnResolve).push(onResolve, deferred); |
| - GET_PRIVATE(this, promiseOnReject).push(onReject, deferred); |
| - break; |
| - case +1: // Resolved |
| - PromiseEnqueue(GET_PRIVATE(this, promiseValue), |
| - [onResolve, deferred], |
| - +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 }); |
| - } |
| - return deferred.promise; |
| + return %_CallFunction(this, onResolve, onReject, false, |
| + PromiseChainInternal); |
| } |
| PromiseCatch = function PromiseCatch(onReject) { |
| @@ -271,10 +290,11 @@ var lastMicrotaskId = 0; |
| function(x) { |
| x = PromiseCoerce(constructor, x); |
| return x === that ? onReject(MakeTypeError('promise_cyclic', [x])) : |
| - IsPromise(x) ? x.then(onResolve, onReject) : onResolve(x); |
| + IsPromise(x) ? x.then(onResolve, onReject) : onResolve(x); |
| }, |
| onReject, |
| - PromiseChain |
| + true, |
| + PromiseChainInternal |
| ); |
| } |
| @@ -343,7 +363,7 @@ var lastMicrotaskId = 0; |
| function PromiseHasUserDefinedRejectHandlerRecursive(promise) { |
| var queue = GET_PRIVATE(promise, promiseOnReject); |
| if (IS_UNDEFINED(queue)) return false; |
| - for (var i = 0; i < queue.length; i += 2) { |
| + for (var i = 0; i < queue.length; i += 3) { |
| if (queue[i] != PromiseIdRejectHandler) return true; |
| if (PromiseHasUserDefinedRejectHandlerRecursive(queue[i + 1].promise)) { |
| return true; |