зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1152902 part 2. Add a fast path for the case when a Promise is resolved with another Promise. r=nsm
This commit is contained in:
Родитель
bc2fcba9c4
Коммит
e5d918e74e
|
@ -201,6 +201,8 @@ protected:
|
|||
ThreadsafeAutoJSContext cx;
|
||||
JS::Rooted<JSObject*> wrapper(cx, mPromise->GetWrapper());
|
||||
MOZ_ASSERT(wrapper); // It was preserved!
|
||||
// If we ever change which compartment we're working in here, make sure to
|
||||
// fix the fast-path for resolved-with-a-Promise in ResolveInternal.
|
||||
JSAutoCompartment ac(cx, wrapper);
|
||||
|
||||
JS::Rooted<JSObject*> resolveFunc(cx,
|
||||
|
@ -1198,6 +1200,35 @@ Promise::ResolveInternal(JSContext* aCx,
|
|||
if (then.isObject() && JS::IsCallable(&then.toObject())) {
|
||||
// This is the then() function of the thenable aValueObj.
|
||||
JS::Rooted<JSObject*> thenObj(aCx, &then.toObject());
|
||||
|
||||
// Add a fast path for the case when we're resolved with an actual
|
||||
// Promise. This has two requirements:
|
||||
//
|
||||
// 1) valueObj is a Promise.
|
||||
// 2) thenObj is a JSFunction backed by our actual Promise::Then
|
||||
// implementation.
|
||||
//
|
||||
// If those requirements are satisfied, then we know exactly what
|
||||
// thenObj.call(valueObj) will do, so we can optimize a bit and avoid ever
|
||||
// entering JS for this stuff.
|
||||
Promise* nextPromise;
|
||||
if (PromiseBinding::IsThenMethod(thenObj) &&
|
||||
NS_SUCCEEDED(UNWRAP_OBJECT(Promise, valueObj, nextPromise))) {
|
||||
// If we were taking the codepath that involves ThenableResolverTask and
|
||||
// PromiseInit below, then eventually, in ThenableResolverTask::Run, we
|
||||
// would create some JSFunctions in the compartment of
|
||||
// this->GetWrapper() and pass them to the PromiseInit. So by the time
|
||||
// we'd see the resolution value it would be wrapped into the
|
||||
// compartment of this->GetWrapper(). The global of that compartment is
|
||||
// this->GetGlobalJSObject(), so use that as the global for
|
||||
// ResolvePromiseCallback/RejectPromiseCallback.
|
||||
JS::Rooted<JSObject*> glob(aCx, GlobalJSObject());
|
||||
nsRefPtr<PromiseCallback> resolveCb = new ResolvePromiseCallback(this, glob);
|
||||
nsRefPtr<PromiseCallback> rejectCb = new RejectPromiseCallback(this, glob);
|
||||
nextPromise->AppendCallbacks(resolveCb, rejectCb);
|
||||
return;
|
||||
}
|
||||
|
||||
nsRefPtr<PromiseInit> thenCallback =
|
||||
new PromiseInit(thenObj, mozilla::dom::GetIncumbentGlobal());
|
||||
nsRefPtr<ThenableResolverTask> task =
|
||||
|
|
|
@ -34,7 +34,7 @@ interface _Promise {
|
|||
|
||||
// The [TreatNonCallableAsNull] annotation is required since then() should do
|
||||
// nothing instead of throwing errors when non-callable arguments are passed.
|
||||
[NewObject]
|
||||
[NewObject, MethodIdentityTestable]
|
||||
Promise<any> then([TreatNonCallableAsNull] optional AnyCallback? fulfillCallback = null,
|
||||
[TreatNonCallableAsNull] optional AnyCallback? rejectCallback = null);
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче