Process Model过程模型
Electron inherits its multi-process architecture from Chromium, which makes the framework architecturally very similar to a modern web browser. Electron继承了Chromium的多进程架构,这使得该框架在架构上非常类似于现代web浏览器。This guide will expand on the concepts applied in the Tutorial.本指南将扩展本教程中应用的概念。
Why not a single process?为什么不采用单一进程?
Web browsers are incredibly complicated applications. Web浏览器是非常复杂的应用程序。Aside from their primary ability to display web content, they have many secondary responsibilities, such as managing multiple windows (or tabs) and loading third-party extensions.除了显示web内容的主要功能外,他们还有许多次要职责,例如管理多个窗口(或选项卡)和加载第三方扩展。
In the earlier days, browsers usually used a single process for all of this functionality. 在早期,浏览器通常使用单个进程来实现所有这些功能。Although this pattern meant less overhead for each tab you had open, it also meant that one website crashing or hanging would affect the entire browser.虽然这种模式意味着你打开的每个标签的开销更少,但它也意味着一个网站崩溃或挂起会影响整个浏览器。
The multi-process model多过程模型
To solve this problem, the Chrome team decided that each tab would render in its own process, limiting the harm that buggy or malicious code on a web page could cause to the app as a whole. 为了解决这个问题,Chrome团队决定每个标签都在自己的进程中呈现,从而限制网页上的错误或恶意代码对整个应用程序造成的危害。A single browser process then controls these processes, as well as the application lifecycle as a whole. 然后,单个浏览器进程控制这些进程以及整个应用程序生命周期。This diagram below from the Chrome Comic visualizes this model:Chrome漫画中的下图显示了该模型:
Electron applications are structured very similarly. Electron应用的结构非常相似。As an app developer, you control two types of processes: main and renderer. 作为应用程序开发人员,您控制两种类型的进程:主进程和渲染器。These are analogous to Chrome's own browser and renderer processes outlined above.这些类似于上述Chrome自己的浏览器和渲染程序。
The main process主进程
Each Electron app has a single main process, which acts as the application's entry point. 每个Electron应用程序都有一个主进程,作为应用程序的入口点。The main process runs in a Node.js environment, meaning it has the ability to 主进程在Node.js环境中运行,这意味着它能够require
modules and use all of Node.js APIs.require
模块并使用所有Node.js API。
Window management窗口管理
The main process' primary purpose is to create and manage application windows with the BrowserWindow module.主要进程的主要目的是使用BrowserWindow模块创建和管理应用程序窗口。
Each instance of the BrowserWindow
class creates an application window that loads a web page in a separate renderer process. BrowserWindow
类的每个实例都创建一个应用程序窗口,该窗口在单独的呈现程序进程中加载网页。You can interact with this web content from the main process using the window's webContents object.您可以使用窗口的webContents对象从主进程与此web内容交互。
const { BrowserWindow } = require('electron')
const win = new BrowserWindow({ width: 800, height: 1500 })
win.loadURL('https://github.com')
const contents = win.webContents
console.log(contents)
Note: A renderer process is also created for web embeds such as the注意:还为web嵌入(如BrowserView
module.BrowserView
模块)创建了渲染器进程。ThewebContents
object is also accessible for embedded web content.WebContents
对象也可用于嵌入式web内容。
Because the 由于BrowserWindow
module is an EventEmitter, you can also add handlers for various user events (for example, minimizing or maximizing your window).BrowserWindow
模块是一个事件发射器,您还可以为各种用户事件添加处理程序(例如,最小化或最大化窗口)。
When a 当BrowserWindow
instance is destroyed, its corresponding renderer process gets terminated as well.BrowserWindow
实例被销毁时,其相应的渲染器进程也会终止。
Application lifecycle应用程序生命周期
The main process also controls your application's lifecycle through Electron's app module. 主进程还通过Electron的app模块控制应用程序的生命周期。This module provides a large set of events and methods that you can use to add custom application behaviour (for instance, programatically quitting your application, modifying the application dock, or showing an About panel).此模块提供了大量事件和方法,可用于添加自定义应用程序行为(例如,以编程方式退出应用程序、修改应用程序坞或显示“关于”面板)。
As a practical example, the app shown in the quick start guide uses 作为一个实际示例,快速入门指南中显示的应用程序使用应用程序API创建更原生的应用程序窗口体验。app
APIs to create a more native application window experience.
// quitting the app when no windows are open on non-macOS platforms
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') app.quit()
})
Native APIs原生API
To extend Electron's features beyond being a Chromium wrapper for web contents, the main process also adds custom APIs to interact with the user's operating system. 为了将Electron的功能扩展到web内容的Chromium包装器之外,主进程还添加了自定义API以与用户的操作系统交互。Electron exposes various modules that control native desktop functionality, such as menus, dialogs, and tray icons.Electron公开了控制本机桌面功能的各种模块,如菜单、对话框和托盘图标。
For a full list of Electron's main process modules, check out our API documentation.有关Electron主要流程模块的完整列表,请查看API文档。
The renderer process渲染器进程
Each Electron app spawns a separate renderer process for each open 每个Electron应用程序为每个打开的BrowserWindow
(and each web embed). BrowserWindow
(和每个web嵌入)生成一个单独的渲染器进程。As its name implies, a renderer is responsible for rendering web content. 顾名思义,呈现器负责呈现web内容。For all intents and purposes, code ran in renderer processes should behave according to web standards (insofar as Chromium does, at least).出于所有意图和目的,渲染器进程中运行的代码应该按照web标准(至少在Chromium的范围内)运行。
Therefore, all user interfaces and app functionality within a single browser window should be written with the same tools and paradigms that you use on the web.因此,单个浏览器窗口中的所有用户界面和应用程序功能都应使用您在web上使用的相同工具和范例编写。
Although explaining every web spec is out of scope for this guide, the bare minimum to understand is:尽管解释每个web规范超出了本指南的范围,但至少要理解以下内容:
An HTML file is your entry point for the renderer process.HTML文件是渲染器进程的入口点。UI styling is added through Cascading Style Sheets (CSS).UI样式是通过层叠样式表(CSS)添加的。Executable JavaScript code can be added through可执行JavaScript代码可以通过<script>
elements.<script>
元素添加。
Moreover, this also means that the renderer has no direct access to 此外,这也意味着渲染器无法直接访问require
or other Node.js APIs. require
或其他Node.js API。In order to directly include NPM modules in the renderer, you must use the same bundler toolchains (for example, 为了在渲染器中直接包含NPM模块,您必须使用web上使用的捆绑工具链(例如,webpack
or parcel
) that you use on the web.webpack
或parcel
)。
Renderer processes can be spawned with a full Node.js environment for ease of development. 渲染器进程可以使用完整的Node.js环境生成,以便于开发。Historically, this used to be the default, but this feature was disabled for security reasons.历史上,这是默认设置,但出于安全原因,此功能被禁用。
At this point, you might be wondering how your renderer process user interfaces can interact with Node.js and Electron's native desktop functionality if these features are only accessible from the main process. 此时,您可能想知道,如果只能从主进程访问这些功能,渲染器进程用户界面如何与Node.js和Electron的本机桌面功能交互。In fact, there is no direct way to import Electron's content scripts.事实上,没有直接的方法导入Electron的内容脚本。
Preload scripts预加载脚本
Preload scripts contain code that executes in a renderer process before its web content begins loading. 预加载脚本包含在其web内容开始加载之前在渲染器进程中执行的代码。These scripts run within the renderer context, but are granted more privileges by having access to Node.js APIs.这些脚本在渲染器上下文中运行,但通过访问Node.js API获得更多特权。
A preload script can be attached to the main process in the 可以在BrowserWindow
constructor's webPreferences
option.BrowserWindow
构造函数的webPreferences
选项中将预加载脚本附加到主进程。
const { BrowserWindow } = require('electron')
//...
const win = new BrowserWindow({
webPreferences: {
preload: 'path/to/preload.js',
},
})
//...
Because the preload script shares a global Window interface with the renderers and can access Node.js APIs, it serves to enhance your renderer by exposing arbitrary APIs in the 由于预加载脚本与渲染器共享一个全局Window接口,并且可以访问Node.js API,因此它通过在window
global that your web contents can then consume.window
全局中公开任意API来增强渲染器,然后web内容可以使用这些API。
Although preload scripts share a 尽管预加载脚本与它们所连接的渲染器共享一个window
global with the renderer they're attached to, you cannot directly attach any variables from the preload script to window
because of the contextIsolation default.window
全局,但由于contextIsolation默认设置,您无法将预加载脚本中的任何变量直接连接到window
。
window.myAPI = {
desktop: true,
}
console.log(window.myAPI)
// => undefined
Context Isolation means that preload scripts are isolated from the renderer's main world to avoid leaking any privileged APIs into your web content's code.上下文隔离意味着预加载脚本与渲染器的主世界隔离,以避免将任何特权API泄漏到web内容的代码中。
Instead, use the contextBridge module to accomplish this securely:相反,请使用contextBridge模块安全地完成此操作:
const { contextBridge } = require('electron')
contextBridge.exposeInMainWorld('myAPI', {
desktop: true,
})
console.log(window.myAPI)
// => { desktop: true }
This feature is incredibly useful for two main purposes:此功能非常有用,主要有两个目的:
By exposing ipcRenderer helpers to the renderer, you can use inter-process communication (IPC) to trigger main process tasks from the renderer (and vice-versa).通过向渲染器公开ipcRenderer助手,可以使用进程间通信(IPC)从渲染器触发主进程任务(反之亦然)。If you're developing an Electron wrapper for an existing web app hosted on a remote URL, you can add custom properties onto the renderer's如果您正在为托管在远程URL上的现有web应用程序开发Electron包装器,则可以将自定义属性添加到渲染器的window
global that can be used for desktop-only logic on the web client's side.window
全局中,该属性可用于web客户端的仅桌面逻辑。