Я тестирую программу CEF3 на Visual Studio 2013 (C ++) и Windows 8.1.
Я хочу обработать нативную функцию, вызванную из JavaScript. Однако пока выполняется нативная функция, браузер зависает. PostTask также не эффективен.
В случае, если поток создан с помощью CreateThread (Win32 API), возникает ошибка при получении CefV8Value в другом потоке.
Есть ли хороший способ асинхронной обработки функции?
CefSettings settings;
settings.single_process = true;
void App::OnContextCreated(
CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefV8Context> context)
{
CoInitializeEx(NULL, COINIT_MULTITHREADED);
// Retrieve the context's window object.
CefRefPtr<CefV8Value> object = context->GetGlobal();
CefRefPtr<CefV8Handler> handler = new AppExtensionHandler(this);
object->SetValue("execNative",
CefV8Value::CreateFunction("execNative", handler),
V8_PROPERTY_ATTRIBUTE_NONE);
}
bool AppExtensionHandler::Execute(const CefString& name,
CefRefPtr<CefV8Value> object,
const CefV8ValueList& arguments,
CefRefPtr<CefV8Value>& retval,
CefString& exception)
{
CefRefPtr<CefBrowser> browser = CefV8Context::GetCurrentContext()->GetBrowser();
if (!browser.get()) return false;
if (name == "execNative") {
Sleep(10000); // heavy process
CefRefPtr<CefFrame> frame = browser->GetMainFrame();
frame->ExecuteJavaScript(L"result(true)", frame->GetURL(), 0);
}
return true;
}
Проблема в том, что обратный вызов JavaScript происходит на Процесс рендеринга клиента CEF. Этот процесс непосредственно отвечает за все взаимодействие с пользователем, клики, выполнение JS и тому подобное. Даже если вы публикуете в другой теме (в том же процессе), это не имеет большого значения, как кажется.
Что вы хотели бы сделать, это отправить это на Процесс браузера и сделайте обработку там. CEF3 часто задаваемые вопросы покрывает это сообщение, если у вас не было необходимости делать это раньше:
[…] Как передать информацию между браузером и процессами рендеринга в CEF3?Для предоставления информации динамически используйте сообщения процесса (
CefProcessMessage
), которые связаны с конкретнымCefBrowser
экземпляр и отправляются с использованиемCefBrowser::SendProcessMessage()
метод. […] Сообщение, отправленное процессом рендеринга в процесс браузера, поступит вCefClient::OnProcessMessageReceived()
, […]
Похоже, что это довольно большое дело в Adobe Brackets-Shell (достаточно популярном WebIDE с открытым исходным кодом, который использует CEF3) — их руководство по расширениям V8 проходит через это очень хорошо.
Всякий раз, когда вызывается нативная функция,
AppShellExtensionHandler::Execute()
вызывается. Этот код выполняется в процессе рендеринга, поэтому здесь должен выполняться только самый простой код расширения. Только для скобокgetElapsedMilliseconds()
обрабатывается здесь. Все остальные вызовы передаются процессу браузера черезCefProcessMessage
,
AppShellExtensionHandler
упомянутое здесь эквивалентно вашему AppExtensionHandler
, Я очень рекомендую просмотреть их код для обработки расширений — это было сделано довольно элегантно. Справедливое предупреждение: я профессионально связан с Adobe, хотя Brackets.io — предприятие с открытым исходным кодом.
Надеюсь, это поможет — ура!
Посмотрите на этот пост. Отлично работает. Решает все мои JS для нативных проблем и использует структурированный подход передачи параметров … и он точно решает проблему, с которой вы тоже сталкиваетесь … вам просто нужно создать пользовательский поток (Task) для обработки вещей в фоновом режиме …
JS на родной через V8Context — асинхронно!
Я проверил это сам, и это работает очень хорошо .. если я что-то упустил …
Хотя в посте описывается C #, перевести его на C ++ будет очень просто