2.10 渲染进程Node.js环境
前面介绍初始化主进程Node.js环境时提到,Electron在启动Chromium时为其传入了一个ElectronMainDelegate的代理对象,在Chromium运行过程中,每创建一个浏览器窗口,也就是说每创建一个渲染进程,就会执行这个代理对象的CreateContentRenderer-Client方法。
CreateContentRendererClient方法会创建一个ElectronRendererClient对象(shell\renderer\electron_renderer_client.cc)。ElectronRendererClient对象间接继承自Chromium的Content-RendererClient类型。这个类型为渲染进程的生命周期暴露出了一系列的事件(姑且称之为事件),比如DidCreateScriptContext(渲染进程的JavaScript执行环境准备就绪)、WillRelease-ScriptContext(将要卸载渲染进程的JavaScript执行环境)等。
Electron就是在DidCreateScriptContext事件中为渲染进程初始化Node.js环境的,代码如下所示:
void ElectronRendererClient::DidCreateScriptContext(v8::Handle<v8::Context>renderer_context, content::RenderFrame* render_frame) { auto prefs = render_frame->GetBlinkPreferences(); bool is_main_frame = render_frame->IsMainFrame(); bool is_devtools = IsDevToolsExtension(render_frame); bool allow_node_in_subframes = prefs.node_integration_in_sub_frames; bool should_load_node = (is_main_frame || is_devtools || allow_node_in_subframes) && !IsWebViewFrame(renderer_context, render_frame); if (!should_load_node) return; injected_frames_.insert(render_frame); if (!node_integration_initialized_) { node_integration_initialized_= true; node_bindings_->Initialize(); node_bindings_->PrepareMessageLoop(); } else { node_bindings_->PrepareMessageLoop(); } if (!node::tracing::TraceEventHelper::GetAgent()) node::tracing::TraceEventHelper::SetAgent(node::CreateAgent()); bool initialized = node::InitializeContext(renderer_context); CHECK(initialized); node::Environment* env = node_bindings_->CreateEnvironment(renderer_context, nullptr); env->set_force_context_aware(true); environments_.insert(env); electron_bindings_->BindTo(env->isolate(), env->process_object()); gin_helper::Dictionary process_dict(env->isolate(), env->process_object()); BindProcess(env->isolate(), &process_dict, render_frame); node_bindings_->LoadEnvironment(env); if (node_bindings_->uv_env() == nullptr) { node_bindings_->set_uv_env(env); node_bindings_->RunMessageLoop(); } }
渲染进程初始化Node.js环境的逻辑与主进程初始化Node.js的逻辑大同小异,值得注意的是,如果开发者没有开启在iframe中初始化Node.js环境的开关,且当前渲染进程是一个iframe页面产生的,那么此方法直接退出,不执行初始化Node.js环境的逻辑。
了解了iframe内是如何初始化Node环境的,接着就看一下WebWorker内是如何初始化Node.js环境的。
这项工作也是由ElectronRendererClient对象完成的,当页面上的WebWorker的JavaScript环境准备完成后,会触发ElectronRendererClient对象的WorkerScriptReadyForEvaluationOnWorkerThread事件,Electron在这个事件的处理方法中执行了为WebWoker初始化Node.js环境的逻辑(shell\renderer\web_worker_observer.cc)。