Return string result from ExecuteJavaScript.

Think CEF could benefit from a new feature or capability? Discuss CEF feature requests here.

Return string result from ExecuteJavaScript.

Postby chillitom » Thu Nov 25, 2010 12:39 pm

It would be fantastic if there was an alternative to CefFrame's ExecuteJavaScript (perhaps called EvaluateJavaScript) which would return the result as a string.

V8's shell (http://code.google.com/p/v8/source/brow ... s/shell.cc) does this to the results of it's evaluation:

Code: Select all
 v8::String::Utf8Value str(result);
chillitom
Techie
 
Posts: 18
Joined: Sat Nov 20, 2010 11:50 am

Re: Return string result from ExecuteJavaScript.

Postby magreenblatt » Fri Nov 26, 2010 12:02 pm

Returning a value from ExecuteJavaScript would require blocking the calling thread. This is a bad idea in most cases but especially in situations where the execution may take a while, as with executing arbitrary JS code. A better option is to have ExecuteJavaScript call back to your code asynchronously. This can be done currently by exposing native function(s) via window binding or V8 extension that the JS code passed to ExecuteJavaScript can call when the task is completed.
magreenblatt
Site Admin
 
Posts: 12382
Joined: Fri May 29, 2009 6:57 pm

Re: Return string result from ExecuteJavaScript.

Postby chillitom » Fri Dec 03, 2010 4:34 am

I agree that blocking isn't always the nicest thing to do but consider this case:

I wish to execute some JavaScript and await the result. If everything goes well the script completes and the result can be passed to an exposed native function, the native function can in turn signal a wait handle to let the waiting thread know that the operation has completed, all well and good.

Now consider that there is a problem with the JavaScript, an exception is raised before the code completes, the native function never gets called and the waiting thread will hang indefinitely.

Some problems can be caught using a try/catch so we could have something like this:

Code: Select all
try
{
// <script> is the inlined contents of the CefFrame->ExecuteJavaScript's jsCode argument.
__native_result_function(<script>);       
}
catch(e)
{
__native_error_function(e);
}


However if <script> is ill formed (e.g. one too many { ) then the script error might never get caught.

If a synchronous api call is out of the question then I'd suggest adding success and failure callbacks be added to the method signature.

Thoughts?
chillitom
Techie
 
Posts: 18
Joined: Sat Nov 20, 2010 11:50 am

Re: Return string result from ExecuteJavaScript.

Postby magreenblatt » Fri Dec 03, 2010 9:36 am

Your application should not block waiting for JavaScript execution to complete. Instead, it should await notification of JavaScript completion asynchronously.

Any errors in JavaScript parsing should be reported to CefHandler::HandleConsoleMessage. Just specify a unique value for the |sciptUrl| argument to CefFrame::ExecuteJavaScript. This notification can then be used by your application to perform any required cancellation actions.
magreenblatt
Site Admin
 
Posts: 12382
Joined: Fri May 29, 2009 6:57 pm

Re: Return string result from ExecuteJavaScript.

Postby chillitom » Fri Dec 03, 2010 12:39 pm

Okay I agree with you on the asynchronous stuff but would it not be possible to have some explicit callback for the completion of a JavaScript call? Only it seems a little awkward trying to repurpose the javascript console message handler for this purpose.

Something like this would be ideal:

Code: Select all
class CefV8AsyncResult
{
   void Success(CefRefPtr<CefV8Value> result, void* user_data) =0;
   void Error(CefRefPtr<CefV8Value> exception, void* user_data) =0;
}

with

Code: Select all
void CefFrame::ExecuteJavaScript(CefString script, CefString scriptName, int lineOffset, CefRefPtr<CefV8AsyncResult> resultHandler, void* user_data);


I'm not familiar with the internals of Chromium, perhaps this isn't possible, what do you think?
chillitom
Techie
 
Posts: 18
Joined: Sat Nov 20, 2010 11:50 am

Re: Return string result from ExecuteJavaScript.

Postby magreenblatt » Fri Dec 03, 2010 1:47 pm

I'm not familiar with the internals of Chromium, perhaps this isn't possible, what do you think?

Nothing is impossible, but I'm not sure this situation is well defined. What happens if the JavaScript code sets a timer that gets executed later on? Is the JavaScript considered complete only after the timer fires?

Regards,
Marshall
magreenblatt
Site Admin
 
Posts: 12382
Joined: Fri May 29, 2009 6:57 pm

Re: Return string result from ExecuteJavaScript.

Postby chillitom » Mon Dec 06, 2010 12:49 pm

In my opinion the callback should get run when the evaluation of the code provided to the method call finishes, if the code has set up timers then these should still run but aren't of concern to the callback. This would make the call's behavior similar to a number of other embeddable/scriptable browser controls, e.g. MSHTML, WebDriver or Watin/Watir.

This functionality can be very useful for automating site testing. You can drive the browser using JavaScript and use more JavaScript to check assertions about the page content but knowing when an action has completed is very important as tests need to be run in the correct order/timing.
chillitom
Techie
 
Posts: 18
Joined: Sat Nov 20, 2010 11:50 am

Re: Return string result from ExecuteJavaScript.

Postby magreenblatt » Mon Dec 06, 2010 1:39 pm

In my opinion the callback should get run when the evaluation of the code provided to the method call finishes, if the code has set up timers then these should still run but aren't of concern to the callback.

OK, I agree. It's probably best to provide the same error information to ExecuteError that is currently passed to CefHandler::HandleConsoleMessage.

Code: Select all
class CefV8ExecutionStateListener : public CefBase
{
  virtual void ExecuteSuccess(CefRefPtr<CefV8Value> result) =0;
  virtual void ExecuteError(const CefString& message, const CefString& source, int line) =0;
};

void CefFrame::ExecuteJavaScript(const CefString& jsCode, const CefString& scriptUrl,
    int startLine, CefRefPtr<CefV8ExecutionStateListener> stateListener);

Should we also have an ExecuteStarting method that's called immediately before the JS execution begins and gives the user one last opportunity to cancel the execution?
magreenblatt
Site Admin
 
Posts: 12382
Joined: Fri May 29, 2009 6:57 pm

Re: Return string result from ExecuteJavaScript.

Postby chillitom » Tue Dec 07, 2010 5:34 am

I like the API you've suggested, the void* to user data that I suggested was redundant and dangerous, no ref counting.

Personally I can't immediately think of cases where I'd make use of an ExecuteStarting callback to cancel execution, others might though. Having a callback just before execution would be useful for measuring performance precisely. If it's easy to implement and you think people might find that useful they I'd say go for it.
chillitom
Techie
 
Posts: 18
Joined: Sat Nov 20, 2010 11:50 am

Re: Return string result from ExecuteJavaScript.

Postby magreenblatt » Tue Dec 07, 2010 9:28 am

I've created an issue to track this:
http://code.google.com/p/chromiumembedd ... ail?id=151

Patches are welcome.
magreenblatt
Site Admin
 
Posts: 12382
Joined: Fri May 29, 2009 6:57 pm

Next

Return to Feature Request Forum

Who is online

Users browsing this forum: No registered users and 11 guests