Add support for native creation and resolution of Promises (fixes issue #3305)

This commit is contained in:
VodBox
2022-10-11 14:54:32 -04:00
committed by Marshall Greenblatt
parent 60ee4a34aa
commit fa643b269e
10 changed files with 609 additions and 9 deletions

View File

@ -1480,6 +1480,33 @@ CefRefPtr<CefV8Value> CefV8Value::CreateFunction(
return impl.get();
}
// static
CefRefPtr<CefV8Value> CefV8Value::CreatePromise() {
CEF_V8_REQUIRE_ISOLATE_RETURN(nullptr);
v8::Isolate* isolate = GetIsolateManager()->isolate();
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Context> context = isolate->GetCurrentContext();
if (context.IsEmpty()) {
NOTREACHED() << "not currently in a V8 context";
return nullptr;
}
v8::Local<v8::Promise::Resolver> promise_resolver =
v8::Promise::Resolver::New(context).ToLocalChecked();
// Create a tracker object that will cause the user data reference to be
// released when the V8 object is destroyed.
V8TrackObject* tracker = new V8TrackObject(isolate);
// Attach the tracker object.
tracker->AttachTo(context, promise_resolver);
CefRefPtr<CefV8ValueImpl> impl = new CefV8ValueImpl(isolate);
impl->InitObject(promise_resolver, tracker);
return impl.get();
}
// CefV8ValueImpl
CefV8ValueImpl::CefV8ValueImpl(v8::Isolate* isolate)
@ -1713,6 +1740,16 @@ bool CefV8ValueImpl::IsFunction() {
}
}
bool CefV8ValueImpl::IsPromise() {
CEF_V8_REQUIRE_MLT_RETURN(false);
if (type_ == TYPE_OBJECT) {
v8::HandleScope handle_scope(handle_->isolate());
return handle_->GetNewV8Handle(false)->IsPromise();
} else {
return false;
}
}
bool CefV8ValueImpl::IsSame(CefRefPtr<CefV8Value> that) {
CEF_V8_REQUIRE_MLT_RETURN(false);
@ -2444,6 +2481,75 @@ CefRefPtr<CefV8Value> CefV8ValueImpl::ExecuteFunctionWithContext(
return retval;
}
bool CefV8ValueImpl::ResolvePromise(CefRefPtr<CefV8Value> arg) {
CEF_V8_REQUIRE_OBJECT_RETURN(false);
v8::Isolate* isolate = handle_->isolate();
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
if (!value->IsPromise()) {
NOTREACHED() << "V8 value is not a Promise";
return false;
}
if (arg.get() && !arg->IsValid()) {
NOTREACHED() << "invalid V8 arg parameter";
return false;
}
v8::Local<v8::Context> context_local = isolate->GetCurrentContext();
v8::Context::Scope context_scope(context_local);
v8::Local<v8::Object> obj = value->ToObject(context_local).ToLocalChecked();
v8::Local<v8::Promise::Resolver> promise =
v8::Local<v8::Promise::Resolver>::Cast(obj);
v8::TryCatch try_catch(isolate);
try_catch.SetVerbose(true);
if (arg.get()) {
promise
->Resolve(context_local,
static_cast<CefV8ValueImpl*>(arg.get())->GetV8Value(true))
.ToChecked();
} else {
promise->Resolve(context_local, v8::Undefined(isolate)).ToChecked();
}
return !HasCaught(context_local, try_catch);
}
bool CefV8ValueImpl::RejectPromise(const CefString& errorMsg) {
CEF_V8_REQUIRE_OBJECT_RETURN(false);
v8::Isolate* isolate = handle_->isolate();
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
if (!value->IsPromise()) {
NOTREACHED() << "V8 value is not a Promise";
return false;
}
v8::Local<v8::Context> context_local = isolate->GetCurrentContext();
v8::Context::Scope context_scope(context_local);
v8::Local<v8::Object> obj = value->ToObject(context_local).ToLocalChecked();
v8::Local<v8::Promise::Resolver> promise =
v8::Local<v8::Promise::Resolver>::Cast(obj);
v8::TryCatch try_catch(isolate);
try_catch.SetVerbose(true);
promise
->Reject(context_local,
v8::Exception::Error(GetV8String(isolate, errorMsg)))
.ToChecked();
return !HasCaught(context_local, try_catch);
}
bool CefV8ValueImpl::HasCaught(v8::Local<v8::Context> context,
v8::TryCatch& try_catch) {
if (try_catch.HasCaught()) {