diff --git a/CefSharp.BrowserSubprocess.Core/Async/JavascriptAsyncMethodCallback.cpp b/CefSharp.BrowserSubprocess.Core/Async/JavascriptAsyncMethodCallback.cpp index b7c6b55967..2de283714c 100644 --- a/CefSharp.BrowserSubprocess.Core/Async/JavascriptAsyncMethodCallback.cpp +++ b/CefSharp.BrowserSubprocess.Core/Async/JavascriptAsyncMethodCallback.cpp @@ -13,13 +13,11 @@ namespace CefSharp { void JavascriptAsyncMethodCallback::Success(const CefRefPtr& result) { - if (_resolve.get() && _context.get() && _context->Enter()) + if (_promise.get() && _context.get() && _context->Enter()) { try { - CefV8ValueList args; - args.push_back(result); - _resolve->ExecuteFunction(nullptr, args); + _promise->ResolvePromise(result); } finally { @@ -30,13 +28,11 @@ namespace CefSharp void JavascriptAsyncMethodCallback::Fail(const CefString& exception) { - if (_reject.get() && _context.get() && _context->Enter()) + if (_promise.get() && _context.get() && _context->Enter()) { try { - CefV8ValueList args; - args.push_back(CefV8Value::CreateString(exception)); - _reject->ExecuteFunction(nullptr, args); + _promise->RejectPromise(exception); } finally { diff --git a/CefSharp.BrowserSubprocess.Core/Async/JavascriptAsyncMethodCallback.h b/CefSharp.BrowserSubprocess.Core/Async/JavascriptAsyncMethodCallback.h index 27411d722b..808563a541 100644 --- a/CefSharp.BrowserSubprocess.Core/Async/JavascriptAsyncMethodCallback.h +++ b/CefSharp.BrowserSubprocess.Core/Async/JavascriptAsyncMethodCallback.h @@ -16,21 +16,19 @@ namespace CefSharp { private: MCefRefPtr _context; - MCefRefPtr _resolve; - MCefRefPtr _reject; + MCefRefPtr _promise; public: - JavascriptAsyncMethodCallback(CefRefPtr context, CefRefPtr resolve, CefRefPtr reject) - :_context(context), _resolve(resolve.get()), _reject(reject.get()) + JavascriptAsyncMethodCallback(CefRefPtr context, CefRefPtr promise) + :_context(context), _promise(promise.get()) { } !JavascriptAsyncMethodCallback() { - _resolve = nullptr; - _reject = nullptr; _context = nullptr; + _promise = nullptr; } ~JavascriptAsyncMethodCallback() diff --git a/CefSharp.BrowserSubprocess.Core/Async/JavascriptAsyncMethodHandler.cpp b/CefSharp.BrowserSubprocess.Core/Async/JavascriptAsyncMethodHandler.cpp index 71628d738f..cece76c0be 100644 --- a/CefSharp.BrowserSubprocess.Core/Async/JavascriptAsyncMethodHandler.cpp +++ b/CefSharp.BrowserSubprocess.Core/Async/JavascriptAsyncMethodHandler.cpp @@ -24,32 +24,10 @@ namespace CefSharp auto context = CefV8Context::GetCurrentContext(); auto frame = context->GetFrame(); - CefRefPtr promiseData; - CefRefPtr promiseException; - //this will create a promise and give us the reject/resolve functions {p: Promise, res: resolve(), rej: reject()} - if (!context->Eval(CefAppUnmanagedWrapper::kPromiseCreatorScript, CefString(), 0, promiseData, promiseException)) - { - LOG(WARNING) << "JavascriptAsyncMethodHandler::Execute promiseData returned exception: " + promiseException->GetMessage().ToString(); - - exception = promiseException->GetMessage(); - - return true; - } - - //when refreshing the browser this is sometimes null, in this case return true and log message - //https://github.com/cefsharp/CefSharp/pull/2446 - if (promiseData == nullptr) - { - LOG(WARNING) << "JavascriptAsyncMethodHandler::Execute promiseData returned nullptr"; - - return true; - } - - retval = promiseData->GetValue("p"); + CefRefPtr promise = CefV8Value::CreatePromise(); + retval = promise; - auto resolve = promiseData->GetValue("res"); - auto reject = promiseData->GetValue("rej"); - auto callback = gcnew JavascriptAsyncMethodCallback(context, resolve, reject); + auto callback = gcnew JavascriptAsyncMethodCallback(context, promise); auto callbackId = _methodCallbackSave->Invoke(callback); auto request = CefProcessMessage::Create(kJavascriptAsyncMethodCallRequest); diff --git a/CefSharp.BrowserSubprocess.Core/BindObjectAsyncHandler.h b/CefSharp.BrowserSubprocess.Core/BindObjectAsyncHandler.h index 9ece880b2b..36311426b2 100644 --- a/CefSharp.BrowserSubprocess.Core/BindObjectAsyncHandler.h +++ b/CefSharp.BrowserSubprocess.Core/BindObjectAsyncHandler.h @@ -165,54 +165,17 @@ namespace CefSharp rootObject->Bind(cachedObjects, context->GetGlobal()); //Objects already bound or ignore cache - CefRefPtr promiseResolve; - CefRefPtr promiseException; - - auto promiseResolveScript = StringUtils::ToNative("Promise.resolve({Success:true, Count:" + cachedObjects->Count + ", Message:'OK'});"); - - if (context->Eval(promiseResolveScript, CefString(), 0, promiseResolve, promiseException)) - { - retval = promiseResolve; - } - else - { - exception = promiseException->GetMessage(); - - return true; - } + auto promiseResolve = CefV8Value::CreatePromise(); + promiseResolve->ResolvePromise(CreateResultObject(cachedObjects->Count, "OK", true)); + retval = promiseResolve; NotifyObjectBound(frame, objectNamesWithBoundStatus); } else { - CefRefPtr promiseData; - CefRefPtr promiseException; - //this will create a promise and give us the reject/resolve functions {p: Promise, res: resolve(), rej: reject()} - if (!context->Eval(CefAppUnmanagedWrapper::kPromiseCreatorScript, CefString(), 0, promiseData, promiseException)) - { - exception = promiseException->GetMessage(); - - return true; - } - - //when refreshing the browser this is sometimes null, in this case return true and log message - //https://github.com/cefsharp/CefSharp/pull/2446 - if (promiseData == nullptr) - { - LOG(WARNING) << "BindObjectAsyncHandler::Execute promiseData returned nullptr"; - - return true; - } - - //return the promose - retval = promiseData->GetValue("p"); - - //References to the promise resolve and reject methods - auto resolve = promiseData->GetValue("res"); - auto reject = promiseData->GetValue("rej"); - - auto callback = gcnew JavascriptAsyncMethodCallback(context, resolve, reject); - + CefRefPtr promise = CefV8Value::CreatePromise(); + retval = promise; + auto callback = gcnew JavascriptAsyncMethodCallback(context, promise); auto request = CefProcessMessage::Create(kJavascriptRootObjectRequest); auto argList = request->GetArgumentList(); @@ -228,23 +191,13 @@ namespace CefSharp else { //Objects already bound or ignore cache - CefRefPtr promiseResolve; - CefRefPtr promiseException; + auto promiseResolve = CefV8Value::CreatePromise(); + promiseResolve->ResolvePromise(CreateResultObject(0, "Object(s) already bound", false)); + retval = promiseResolve; - auto promiseResolveScript = CefString("Promise.resolve({Success:false, Count:0, Message:'Object(s) already bound'});"); - - if (context->Eval(promiseResolveScript, CefString(), 0, promiseResolve, promiseException)) + if (notifyIfAlreadyBound) { - retval = promiseResolve; - - if (notifyIfAlreadyBound) - { - NotifyObjectBound(frame, objectNamesWithBoundStatus); - } - } - else - { - exception = promiseException->GetMessage(); + NotifyObjectBound(frame, objectNamesWithBoundStatus); } } } @@ -267,6 +220,25 @@ namespace CefSharp return true; } + static CefRefPtr CreateResultObject(int count, String^ message, bool isSuccess) + { + auto response = CefV8Value::CreateObject(nullptr, nullptr); + + const auto countResult = CefV8Value::CreateInt(count); + const auto messageResult = CefV8Value::CreateString(StringUtils::ToNative(message)); + const auto successResult = CefV8Value::CreateBool(isSuccess); + + response->SetValue("Count", countResult, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_READONLY); + response->SetValue("Message", messageResult, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_READONLY); + response->SetValue("Success", successResult, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_READONLY); + + response->SetValue("count", countResult, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_READONLY); + response->SetValue("message", messageResult, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_READONLY); + response->SetValue("success", successResult, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_READONLY); + + return response; + } + private: void NotifyObjectBound(const CefRefPtr frame, List^>^ objectNamesWithBoundStatus) { diff --git a/CefSharp.BrowserSubprocess.Core/CefAppUnmanagedWrapper.cpp b/CefSharp.BrowserSubprocess.Core/CefAppUnmanagedWrapper.cpp index a7b2ceb1f3..02abd5e807 100644 --- a/CefSharp.BrowserSubprocess.Core/CefAppUnmanagedWrapper.cpp +++ b/CefSharp.BrowserSubprocess.Core/CefAppUnmanagedWrapper.cpp @@ -35,16 +35,6 @@ namespace CefSharp { namespace BrowserSubprocess { - const CefString CefAppUnmanagedWrapper::kPromiseCreatorScript = "" - "(function()" - "{" - " var result = {};" - " var promise = new Promise(function(resolve, reject) {" - " result.res = resolve; result.rej = reject;" - " });" - " result.p = promise;" - " return result;" - "})();"; const CefString kRenderProcessId = CefString("RenderProcessId"); const CefString kRenderProcessIdCamelCase = CefString("renderProcessId"); @@ -662,23 +652,15 @@ namespace CefSharp if (_registerBoundObjectRegistry->TryGetAndRemoveMethodCallback(callbackId, callback)) { - //Response object has no Accessor or Interceptor - auto response = CefV8Value::CreateObject(nullptr, nullptr); - - response->SetValue("Count", CefV8Value::CreateInt(javascriptObjects->Count), CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_READONLY); if (javascriptObjects->Count > 0) { //TODO: JSB Should we include a list of successfully bound object names? - response->SetValue("Success", CefV8Value::CreateBool(true), CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_READONLY); - response->SetValue("Message", CefV8Value::CreateString("OK"), CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_READONLY); - callback->Success(response); + callback->Success(BindObjectAsyncHandler::CreateResultObject(javascriptObjects->Count, "OK", true)); } else { - response->SetValue("Success", CefV8Value::CreateBool(false), CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_READONLY); - response->SetValue("Message", CefV8Value::CreateString("Zero objects bounds"), CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_READONLY); - callback->Success(response); + callback->Success(BindObjectAsyncHandler::CreateResultObject(javascriptObjects->Count, "Zero objects bounds", false)); } //Send message notifying Browser Process of which objects were bound diff --git a/CefSharp.BrowserSubprocess.Core/CefAppUnmanagedWrapper.h b/CefSharp.BrowserSubprocess.Core/CefAppUnmanagedWrapper.h index 38f8da2881..c22b2ec4c2 100644 --- a/CefSharp.BrowserSubprocess.Core/CefAppUnmanagedWrapper.h +++ b/CefSharp.BrowserSubprocess.Core/CefAppUnmanagedWrapper.h @@ -40,7 +40,6 @@ namespace CefSharp gcroot _registerBoundObjectRegistry; public: - static const CefString kPromiseCreatorScript; CefAppUnmanagedWrapper(IRenderProcessHandler^ handler, List^ schemes, bool enableFocusedNodeChanged, Action^ onBrowserCreated, Action^ onBrowserDestroyed) : SubProcessApp(schemes) { diff --git a/CefSharp.Example/Resources/BindingTestAsync.js b/CefSharp.Example/Resources/BindingTestAsync.js index 7defa87416..daa47cbaa4 100644 --- a/CefSharp.Example/Resources/BindingTestAsync.js +++ b/CefSharp.Example/Resources/BindingTestAsync.js @@ -286,4 +286,22 @@ QUnit.module('BindingTestAsync', (hooks) => assert.ok(window.boundAsync2 === undefined, "boundAsync2 is now undefined"); }); + QUnit.test("Validate BindObjectAsync result object fields:", async (assert) => + { + const response = await CefSharp.BindObjectAsync({ NotifyIfAlreadyBound: true, IgnoreCache: true }, "boundAsync2"); + const keys = Object.getOwnPropertyDescriptors(response); + + assert.equal(!!keys["count"], true, "count"); + assert.equal(!!keys["Count"], true, "Count"); + + assert.equal(!!keys["message"], true, "message"); + assert.equal(!!keys["Message"], true, "Message"); + + assert.equal(!!keys["success"], true, "success"); + assert.equal(!!keys["Success"], true, "Success"); + + assert.equal(true, CefSharp.DeleteBoundObject("boundAsync2"), "Object was unbound"); + assert.ok(window.boundAsync2 === undefined, "boundAsync2 is now undefined"); + }); + });