Index: src/js/promise.js |
diff --git a/src/js/promise.js b/src/js/promise.js |
index bcf826a10151d48a498d40e72f418805a5022f18..65a8bf3f4ddf0ec598c7c0a21067dff943a5ea66 100644 |
--- a/src/js/promise.js |
+++ b/src/js/promise.js |
@@ -17,12 +17,13 @@ var promiseCombinedDeferredSymbol = |
utils.ImportNow("promise_combined_deferred_symbol"); |
var promiseHasHandlerSymbol = |
utils.ImportNow("promise_has_handler_symbol"); |
-var promiseOnRejectSymbol = utils.ImportNow("promise_on_reject_symbol"); |
-var promiseOnResolveSymbol = |
- utils.ImportNow("promise_on_resolve_symbol"); |
+var promiseRejectReactionsSymbol = |
+ utils.ImportNow("promise_reject_reactions_symbol"); |
+var promiseFulfillReactionsSymbol = |
+ utils.ImportNow("promise_fulfill_reactions_symbol"); |
var promiseRawSymbol = utils.ImportNow("promise_raw_symbol"); |
-var promiseStatusSymbol = utils.ImportNow("promise_status_symbol"); |
-var promiseValueSymbol = utils.ImportNow("promise_value_symbol"); |
+var promiseStateSymbol = utils.ImportNow("promise_state_symbol"); |
+var promiseResultSymbol = utils.ImportNow("promise_result_symbol"); |
var SpeciesConstructor; |
var toStringTagSymbol = utils.ImportNow("to_string_tag_symbol"); |
@@ -33,22 +34,32 @@ utils.Import(function(from) { |
// ------------------------------------------------------------------- |
-// Status values: 0 = pending, +1 = resolved, -1 = rejected |
+// [[PromiseState]] values: |
+const kPending = 0; |
+const kFulfilled = +1; |
+const kRejected = -1; |
+ |
var lastMicrotaskId = 0; |
+// ES#sec-createresolvingfunctions |
+// CreateResolvingFunctions ( promise ) |
function CreateResolvingFunctions(promise) { |
var alreadyResolved = false; |
+ // ES#sec-promise-resolve-functions |
+ // Promise Resolve Functions |
var resolve = value => { |
if (alreadyResolved === true) return; |
alreadyResolved = true; |
- PromiseResolve(promise, value); |
+ FulfillPromise(promise, value); |
}; |
+ // ES#sec-promise-reject-functions |
+ // Promise Reject Functions |
var reject = reason => { |
if (alreadyResolved === true) return; |
alreadyResolved = true; |
- PromiseReject(promise, reason); |
+ RejectPromise(promise, reason); |
}; |
return { |
@@ -59,13 +70,16 @@ function CreateResolvingFunctions(promise) { |
} |
+// ES#sec-promise-executor |
+// Promise ( executor ) |
var GlobalPromise = function Promise(resolver) { |
if (resolver === promiseRawSymbol) { |
return %_NewObject(GlobalPromise, new.target); |
} |
if (IS_UNDEFINED(new.target)) throw MakeTypeError(kNotAPromise, this); |
- if (!IS_CALLABLE(resolver)) |
+ if (!IS_CALLABLE(resolver)) { |
throw MakeTypeError(kResolverNotAFunction, resolver); |
+ } |
var promise = PromiseInit(%_NewObject(GlobalPromise, new.target)); |
var callbacks = CreateResolvingFunctions(promise); |
@@ -85,27 +99,27 @@ var GlobalPromise = function Promise(resolver) { |
// Core functionality. |
function PromiseSet(promise, status, value, onResolve, onReject) { |
- SET_PRIVATE(promise, promiseStatusSymbol, status); |
- SET_PRIVATE(promise, promiseValueSymbol, value); |
- SET_PRIVATE(promise, promiseOnResolveSymbol, onResolve); |
- SET_PRIVATE(promise, promiseOnRejectSymbol, onReject); |
+ SET_PRIVATE(promise, promiseStateSymbol, status); |
+ SET_PRIVATE(promise, promiseResultSymbol, value); |
+ SET_PRIVATE(promise, promiseFulfillReactionsSymbol, onResolve); |
+ SET_PRIVATE(promise, promiseRejectReactionsSymbol, onReject); |
return promise; |
} |
function PromiseCreateAndSet(status, value) { |
var promise = new GlobalPromise(promiseRawSymbol); |
// If debug is active, notify about the newly created promise first. |
- if (DEBUG_IS_ACTIVE) PromiseSet(promise, 0, UNDEFINED); |
+ if (DEBUG_IS_ACTIVE) PromiseSet(promise, kPending, UNDEFINED); |
return PromiseSet(promise, status, value); |
} |
function PromiseInit(promise) { |
return PromiseSet( |
- promise, 0, UNDEFINED, new InternalArray, new InternalArray) |
+ promise, kPending, UNDEFINED, new InternalArray, new InternalArray) |
} |
function PromiseDone(promise, status, value, promiseQueue) { |
- if (GET_PRIVATE(promise, promiseStatusSymbol) === 0) { |
+ if (GET_PRIVATE(promise, promiseStateSymbol) === kPending) { |
var tasks = GET_PRIVATE(promise, promiseQueue); |
if (tasks.length) PromiseEnqueue(value, tasks, status); |
PromiseSet(promise, status, value); |
@@ -139,7 +153,7 @@ function PromiseEnqueue(value, tasks, status) { |
}); |
if (instrumenting) { |
id = ++lastMicrotaskId; |
- name = status > 0 ? "Promise.resolve" : "Promise.reject"; |
+ name = status === kFulfilled ? "Promise.resolve" : "Promise.reject"; |
%DebugAsyncTaskEvent({ type: "enqueue", id: id, name: name }); |
} |
} |
@@ -154,24 +168,27 @@ function PromiseNopResolver() {} |
// For bootstrapper. |
+// ES#sec-ispromise IsPromise ( x ) |
function IsPromise(x) { |
- return IS_RECEIVER(x) && HAS_DEFINED_PRIVATE(x, promiseStatusSymbol); |
+ return IS_RECEIVER(x) && HAS_DEFINED_PRIVATE(x, promiseStateSymbol); |
} |
function PromiseCreate() { |
return new GlobalPromise(PromiseNopResolver) |
} |
-function PromiseResolve(promise, x) { |
+// ES#sec-fulfillpromise |
+// FulfillPromise ( promise, value) |
+function FulfillPromise(promise, x) { |
if (x === promise) { |
- return PromiseReject(promise, MakeTypeError(kPromiseCyclic, x)); |
+ return RejectPromise(promise, MakeTypeError(kPromiseCyclic, x)); |
} |
if (IS_RECEIVER(x)) { |
// 25.4.1.3.2 steps 8-12 |
try { |
var then = x.then; |
} catch (e) { |
- return PromiseReject(promise, e); |
+ return RejectPromise(promise, e); |
} |
if (IS_CALLABLE(then)) { |
// PromiseResolveThenableJob |
@@ -198,22 +215,26 @@ function PromiseResolve(promise, x) { |
return; |
} |
} |
- PromiseDone(promise, +1, x, promiseOnResolveSymbol); |
+ PromiseDone(promise, kFulfilled, x, promiseFulfillReactionsSymbol); |
} |
-function PromiseReject(promise, r) { |
+// ES#sec-rejectpromise |
+// RejectPromise ( promise, reason ) |
+function RejectPromise(promise, r) { |
// Check promise status to confirm that this reject has an effect. |
// Call runtime for callbacks to the debugger or for unhandled reject. |
- if (GET_PRIVATE(promise, promiseStatusSymbol) == 0) { |
+ if (GET_PRIVATE(promise, promiseStateSymbol) === kPending) { |
var debug_is_active = DEBUG_IS_ACTIVE; |
if (debug_is_active || |
!HAS_DEFINED_PRIVATE(promise, promiseHasHandlerSymbol)) { |
%PromiseRejectEvent(promise, r, debug_is_active); |
} |
} |
- PromiseDone(promise, -1, r, promiseOnRejectSymbol) |
+ PromiseDone(promise, kRejected, r, promiseRejectReactionsSymbol) |
} |
+// ES#sec-newpromisecapability |
+// NewPromiseCapability ( C ) |
function NewPromiseCapability(C) { |
if (C === GlobalPromise) { |
// Optimized case, avoid extra closure. |
@@ -240,23 +261,27 @@ function NewPromiseCapability(C) { |
return result; |
} |
-function PromiseDeferred() { |
+// Unspecified V8-specific legacy function |
+function PromiseDefer() { |
%IncrementUseCounter(kPromiseDefer); |
return NewPromiseCapability(this); |
} |
-function PromiseResolved(x) { |
+// Unspecified V8-specific legacy function |
+function PromiseAccept(x) { |
%IncrementUseCounter(kPromiseAccept); |
- return %_Call(PromiseCast, this, x); |
+ return %_Call(PromiseResolve, this, x); |
} |
-function PromiseRejected(r) { |
+// ES#sec-promise.reject |
+// Promise.reject ( x ) |
+function PromiseReject(r) { |
if (!IS_RECEIVER(this)) { |
- throw MakeTypeError(kCalledOnNonObject, PromiseRejected); |
+ throw MakeTypeError(kCalledOnNonObject, PromiseResolve); |
} |
if (this === GlobalPromise) { |
// Optimized case, avoid extra closure. |
- var promise = PromiseCreateAndSet(-1, r); |
+ var promise = PromiseCreateAndSet(kRejected, 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); |
@@ -268,10 +293,11 @@ function PromiseRejected(r) { |
} |
} |
+// ES#sec-promise.prototype.then |
+// Promise.prototype.then ( onFulfilled, onRejected ) |
// Multi-unwrapped chaining with thenable coercion. |
- |
function PromiseThen(onResolve, onReject) { |
- var status = GET_PRIVATE(this, promiseStatusSymbol); |
+ var status = GET_PRIVATE(this, promiseStateSymbol); |
if (IS_UNDEFINED(status)) { |
throw MakeTypeError(kNotAPromise, this); |
} |
@@ -281,24 +307,25 @@ function PromiseThen(onResolve, onReject) { |
onReject = IS_CALLABLE(onReject) ? onReject : PromiseIdRejectHandler; |
var deferred = NewPromiseCapability(constructor); |
switch (status) { |
- case 0: // Pending |
- GET_PRIVATE(this, promiseOnResolveSymbol).push(onResolve, deferred); |
- GET_PRIVATE(this, promiseOnRejectSymbol).push(onReject, deferred); |
+ case kPending: |
+ GET_PRIVATE(this, promiseFulfillReactionsSymbol).push(onResolve, |
+ deferred); |
+ GET_PRIVATE(this, promiseRejectReactionsSymbol).push(onReject, deferred); |
break; |
- case +1: // Resolved |
- PromiseEnqueue(GET_PRIVATE(this, promiseValueSymbol), |
+ case kFulfilled: |
+ PromiseEnqueue(GET_PRIVATE(this, promiseResultSymbol), |
[onResolve, deferred], |
- +1); |
+ kFulfilled); |
break; |
- case -1: // Rejected |
+ case kRejected: |
if (!HAS_DEFINED_PRIVATE(this, promiseHasHandlerSymbol)) { |
// Promise has already been rejected, but had no handler. |
// Revoke previously triggered reject event. |
%PromiseRevokeReject(this); |
} |
- PromiseEnqueue(GET_PRIVATE(this, promiseValueSymbol), |
+ PromiseEnqueue(GET_PRIVATE(this, promiseResultSymbol), |
[onReject, deferred], |
- -1); |
+ kRejected); |
break; |
} |
// Mark this promise as having handler. |
@@ -306,21 +333,26 @@ function PromiseThen(onResolve, onReject) { |
return deferred.promise; |
} |
+// Unspecified V8-specific legacy function |
// Chain is left around for now as an alias for then |
function PromiseChain(onResolve, onReject) { |
%IncrementUseCounter(kPromiseChain); |
return %_Call(PromiseThen, this, onResolve, onReject); |
} |
+// ES#sec-promise.prototype.catch |
+// Promise.prototype.catch ( onRejected ) |
function PromiseCatch(onReject) { |
return this.then(UNDEFINED, onReject); |
} |
// Combinators. |
-function PromiseCast(x) { |
+// ES#sec-promise.resolve |
+// Promise.resolve ( x ) |
+function PromiseResolve(x) { |
if (!IS_RECEIVER(this)) { |
- throw MakeTypeError(kCalledOnNonObject, PromiseCast); |
+ throw MakeTypeError(kCalledOnNonObject, PromiseResolve); |
} |
if (IsPromise(x) && x.constructor === this) return x; |
@@ -329,6 +361,8 @@ function PromiseCast(x) { |
return promiseCapability.promise; |
} |
+// ES#sec-promise.all |
+// Promise.all ( iterable ) |
function PromiseAll(iterable) { |
if (!IS_RECEIVER(this)) { |
throw MakeTypeError(kCalledOnNonObject, "Promise.all"); |
@@ -378,6 +412,8 @@ function PromiseAll(iterable) { |
return deferred.promise; |
} |
+// ES#sec-promise.race |
+// Promise.race ( iterable ) |
function PromiseRace(iterable) { |
if (!IS_RECEIVER(this)) { |
throw MakeTypeError(kCalledOnNonObject, PromiseRace); |
@@ -399,7 +435,7 @@ function PromiseRace(iterable) { |
// Utility for debugger |
function PromiseHasUserDefinedRejectHandlerRecursive(promise) { |
- var queue = GET_PRIVATE(promise, promiseOnRejectSymbol); |
+ var queue = GET_PRIVATE(promise, promiseRejectReactionsSymbol); |
if (IS_UNDEFINED(queue)) return false; |
for (var i = 0; i < queue.length; i += 2) { |
var handler = queue[i]; |
@@ -432,10 +468,10 @@ function PromiseHasUserDefinedRejectHandler() { |
DONT_ENUM | READ_ONLY); |
utils.InstallFunctions(GlobalPromise, DONT_ENUM, [ |
- "reject", PromiseRejected, |
+ "reject", PromiseReject, |
"all", PromiseAll, |
"race", PromiseRace, |
- "resolve", PromiseCast |
+ "resolve", PromiseResolve |
]); |
utils.InstallFunctions(GlobalPromise.prototype, DONT_ENUM, [ |
@@ -448,8 +484,8 @@ utils.InstallFunctions(GlobalPromise.prototype, DONT_ENUM, [ |
"promise_chain", PromiseChain, |
"promise_create", PromiseCreate, |
"promise_has_user_defined_reject_handler", PromiseHasUserDefinedRejectHandler, |
- "promise_reject", PromiseReject, |
- "promise_resolve", PromiseResolve, |
+ "promise_reject", RejectPromise, |
+ "promise_resolve", FulfillPromise, |
"promise_then", PromiseThen, |
]); |
@@ -458,18 +494,18 @@ utils.InstallFunctions(GlobalPromise.prototype, DONT_ENUM, [ |
// promise without having to hold on to those closures forever. |
utils.InstallFunctions(extrasUtils, 0, [ |
"createPromise", PromiseCreate, |
- "resolvePromise", PromiseResolve, |
- "rejectPromise", PromiseReject |
+ "resolvePromise", FulfillPromise, |
+ "rejectPromise", RejectPromise |
]); |
// TODO(v8:4567): Allow experimental natives to remove function prototype |
-[PromiseChain, PromiseDeferred, PromiseResolved].forEach( |
+[PromiseChain, PromiseDefer, PromiseAccept].forEach( |
fn => %FunctionRemovePrototype(fn)); |
utils.Export(function(to) { |
to.PromiseChain = PromiseChain; |
- to.PromiseDeferred = PromiseDeferred; |
- to.PromiseResolved = PromiseResolved; |
+ to.PromiseDefer = PromiseDefer; |
+ to.PromiseAccept = PromiseAccept; |
}); |
}) |