Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2028)

Unified Diff: src/js/promise.js

Issue 1501763004: Revert of Clean up promises and fix an edge case bug (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 5 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | test/mjsunit/es6/promises.js » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/js/promise.js
diff --git a/src/js/promise.js b/src/js/promise.js
index f59809f0bd6034cd7b6e6f3beb977e89fd0c4995..1016cbba29be3fbf6afa3cdd8e159a5517a7d96f 100644
--- a/src/js/promise.js
+++ b/src/js/promise.js
@@ -40,6 +40,9 @@
var resolve = function(value) {
if (alreadyResolved === true) return;
alreadyResolved = true;
+ if (value === promise) {
+ return PromiseReject(promise, MakeTypeError(kPromiseCyclic, value));
+ }
PromiseResolve(promise, value);
};
@@ -113,11 +116,37 @@
}
}
+function PromiseCoerce(constructor, x) {
+ if (!IsPromise(x) && IS_SPEC_OBJECT(x)) {
+ var then;
+ try {
+ then = x.then;
+ } catch(r) {
+ return %_Call(PromiseRejected, constructor, r);
+ }
+ if (IS_CALLABLE(then)) {
+ var deferred = NewPromiseCapability(constructor);
+ try {
+ %_Call(then, x, deferred.resolve, deferred.reject);
+ } catch(r) {
+ deferred.reject(r);
+ }
+ return deferred.promise;
+ }
+ }
+ return x;
+}
+
function PromiseHandle(value, handler, deferred) {
try {
%DebugPushPromise(deferred.promise, PromiseHandle);
var result = handler(value);
- deferred.resolve(result);
+ if (result === deferred.promise)
+ throw MakeTypeError(kPromiseCyclic, result);
+ else if (IsPromise(result))
+ %_Call(PromiseChain, result, deferred.resolve, deferred.reject);
+ else
+ deferred.resolve(result);
} catch (exception) {
try { deferred.reject(exception); } catch (e) { }
} finally {
@@ -164,29 +193,28 @@
}
function PromiseResolve(promise, x) {
- if (x === promise) {
- return PromiseReject(promise, MakeTypeError(kPromiseCyclic, x));
- }
- if (IS_SPEC_OBJECT(x)) {
- // 25.4.1.3.2 steps 8-12
- try {
- var then = x.then;
- } catch (e) {
- return PromiseReject(promise, e);
- }
- if (IS_CALLABLE(then)) {
- // PromiseResolveThenableJob
- return %EnqueueMicrotask(function() {
- try {
- var callbacks = CreateResolvingFunctions(promise);
- %_Call(then, x, callbacks.resolve, callbacks.reject);
- } catch (e) {
- PromiseReject(promise, e);
- }
- });
- }
- }
- PromiseDone(promise, +1, x, promiseOnResolveSymbol);
+ if (GET_PRIVATE(promise, promiseStatusSymbol) === 0) {
+ if (IS_SPEC_OBJECT(x)) {
+ // 25.4.1.3.2 steps 8-12
+ try {
+ var then = x.then;
+ } catch (e) {
+ return PromiseReject(promise, e);
+ }
+ if (IS_CALLABLE(then)) {
+ // PromiseResolveThenableJob
+ return %EnqueueMicrotask(function() {
+ try {
+ var callbacks = CreateResolvingFunctions(promise);
+ %_Call(then, x, callbacks.resolve, callbacks.reject);
+ } catch (e) {
+ PromiseReject(promise, e);
+ }
+ });
+ }
+ }
+ PromiseDone(promise, +1, x, promiseOnResolveSymbol);
+ }
}
function PromiseReject(promise, r) {
@@ -217,7 +245,6 @@
} else {
var result = {promise: UNDEFINED, resolve: UNDEFINED, reject: UNDEFINED };
result.promise = new C(function(resolve, reject) {
- // TODO(littledan): Check for resolve and reject being not undefined
result.resolve = resolve;
result.reject = reject;
});
@@ -230,13 +257,15 @@
}
function PromiseResolved(x) {
- return %_Call(PromiseCast, this, x);
+ if (this === GlobalPromise) {
+ // Optimized case, avoid extra closure.
+ return PromiseCreateAndSet(+1, x);
+ } else {
+ return new this(function(resolve, reject) { resolve(x) });
+ }
}
function PromiseRejected(r) {
- if (!IS_SPEC_OBJECT(this)) {
- throw MakeTypeError(kCalledOnNonObject, PromiseRejected);
- }
var promise;
if (this === GlobalPromise) {
// Optimized case, avoid extra closure.
@@ -250,18 +279,15 @@
return promise;
}
-// Multi-unwrapped chaining with thenable coercion.
-
-function PromiseThen(onResolve, onReject) {
- var constructor = this.constructor;
- onResolve = IS_CALLABLE(onResolve) ? onResolve : PromiseIdResolveHandler;
- onReject = IS_CALLABLE(onReject) ? onReject : PromiseIdRejectHandler;
+// Simple chaining.
+
+// PromiseChain a.k.a. flatMap
+function PromiseChainInternal(constructor, onResolve, onReject) {
+ onResolve = IS_UNDEFINED(onResolve) ? PromiseIdResolveHandler : onResolve;
+ onReject = IS_UNDEFINED(onReject) ? PromiseIdRejectHandler : onReject;
var deferred = NewPromiseCapability(constructor);
switch (GET_PRIVATE(this, promiseStatusSymbol)) {
case UNDEFINED:
- // TODO(littledan): The type check should be called before
- // constructing NewPromiseCapability; this is observable when
- // erroneously copying this method to other classes.
throw MakeTypeError(kNotAPromise, this);
case 0: // Pending
GET_PRIVATE(this, promiseOnResolveSymbol).push(onResolve, deferred);
@@ -291,25 +317,47 @@
return deferred.promise;
}
-// Chain is left around for now as an alias for then
function PromiseChain(onResolve, onReject) {
- return %_Call(PromiseThen, this, onResolve, onReject);
+ return %_Call(PromiseChainInternal, this, this.constructor,
+ onResolve, onReject);
}
function PromiseCatch(onReject) {
return this.then(UNDEFINED, onReject);
}
+// Multi-unwrapped chaining with thenable coercion.
+
+function PromiseThen(onResolve, onReject) {
+ onResolve = IS_CALLABLE(onResolve) ? onResolve : PromiseIdResolveHandler;
+ onReject = IS_CALLABLE(onReject) ? onReject : PromiseIdRejectHandler;
+ var that = this;
+ var constructor = this.constructor;
+ return %_Call(
+ PromiseChainInternal,
+ this,
+ constructor,
+ function(x) {
+ x = PromiseCoerce(constructor, x);
+ if (x === that) {
+ return onReject(MakeTypeError(kPromiseCyclic, x));
+ } else if (IsPromise(x)) {
+ return x.then(onResolve, onReject);
+ } else {
+ return onResolve(x);
+ }
+ },
+ onReject
+ );
+}
+
// Combinators.
function PromiseCast(x) {
- if (!IS_SPEC_OBJECT(this)) {
- throw MakeTypeError(kCalledOnNonObject, PromiseCast);
- }
if (IsPromise(x) && x.constructor === this) {
return x;
} else {
- return new this(function(resolve, reject) { resolve(x) });
+ return new this(function(resolve) { resolve(x) });
}
}
« no previous file with comments | « no previous file | test/mjsunit/es6/promises.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698