W3Cschool
恭喜您成為首批注冊(cè)用戶
獲得88經(jīng)驗(yàn)值獎(jiǎng)勵(lì)
Electron 繼承了來(lái)自 Chromium 的多進(jìn)程架構(gòu),這使得此框架在架構(gòu)上非常相似于一個(gè)現(xiàn)代的網(wǎng)頁(yè)瀏覽器。 本指南將對(duì) 教程 中應(yīng)用的概念進(jìn)行拓展。
網(wǎng)頁(yè)瀏覽器是個(gè)極其復(fù)雜的應(yīng)用程序。 除了顯示網(wǎng)頁(yè)內(nèi)容的主要能力之外,他們還有許多次要的職責(zé),例如:管理眾多窗口 ( 或 標(biāo)簽頁(yè) ) 和加載第三方擴(kuò)展。
在早期,瀏覽器通常使用單個(gè)進(jìn)程來(lái)處理所有這些功能。 雖然這種模式意味著您打開(kāi)每個(gè)標(biāo)簽頁(yè)的開(kāi)銷較少,但也同時(shí)意味著一個(gè)網(wǎng)站的崩潰或無(wú)響應(yīng)會(huì)影響到整個(gè)瀏覽器。
為了解決這個(gè)問(wèn)題,Chrome 團(tuán)隊(duì)決定讓每個(gè)標(biāo)簽頁(yè)在自己的進(jìn)程中渲染, 從而限制了一個(gè)網(wǎng)頁(yè)上的有誤或惡意代碼可能導(dǎo)致的對(duì)整個(gè)應(yīng)用程序造成的傷害。 然后用單個(gè)瀏覽器進(jìn)程控制這些標(biāo)簽頁(yè)進(jìn)程,以及整個(gè)應(yīng)用程序的生命周期。 下方來(lái)自 Chrome 漫畫(huà) 的圖表可視化了此模型:
Electron 應(yīng)用程序的結(jié)構(gòu)非常相似。 作為應(yīng)用開(kāi)發(fā)者,你將控制兩種類型的進(jìn)程:主進(jìn)程 和 渲染器進(jìn)程。 這類似于上文所述的 Chrome 的瀏覽器和渲染器進(jìn)程。
每個(gè) Electron 應(yīng)用都有一個(gè)單一的主進(jìn)程,作為應(yīng)用程序的入口點(diǎn)。 主進(jìn)程在 Node.js 環(huán)境中運(yùn)行,這意味著它具有 require
模塊和使用所有 Node.js API 的能力。
主進(jìn)程的主要目的是使用 ?BrowserWindow
? 模塊創(chuàng)建和管理應(yīng)用程序窗口。
?BrowserWindow
? 類的每個(gè)實(shí)例創(chuàng)建一個(gè)應(yīng)用程序窗口,且在單獨(dú)的渲染器進(jìn)程中加載一個(gè)網(wǎng)頁(yè)。 您可從主進(jìn)程用 window 的 ?webContent
? 對(duì)象與網(wǎng)頁(yè)內(nèi)容進(jìn)行交互。
const { BrowserWindow } = require('electron')
const win = new BrowserWindow({ width: 800, height: 1500 })
win.loadURL('https://github.com')
const contents = win.webContents
console.log(contents)
注意:渲染器進(jìn)程也是為 web 嵌入 而被創(chuàng)建的,例如 ?
BrowserView
? 模塊。 嵌入式網(wǎng)頁(yè)內(nèi)容也可訪問(wèn) ?webContents
? 對(duì)象。
由于 BrowserWindow
模塊是一個(gè) EventEmitter
, 所以您也可以為各種用戶事件 ( 例如,最小化 或 最大化您的窗口 ) 添加處理程序。
當(dāng)一個(gè) BrowserWindow
實(shí)例被銷毀時(shí),與其相應(yīng)的渲染器進(jìn)程也會(huì)被終止。
主進(jìn)程還能通過(guò) Electron 的 ?app
? 模塊來(lái)控制您應(yīng)用程序的生命周期。 該模塊提供了一整套的事件和方法,可以讓您用來(lái)添加自定義的應(yīng)用程序行為 (例如:以編程方式退出您的應(yīng)用程序、修改應(yīng)用程序塢,或顯示一個(gè)關(guān)于面板) 。
這是一個(gè)實(shí)際的例子,這個(gè)app來(lái)源于 快速入門(mén),用 app
API 創(chuàng)建了一個(gè)更原生的應(yīng)用程序窗口體驗(yàn)。
// quitting the app when no windows are open on non-macOS platforms
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') app.quit()
})
為了使 Electron 的功能不僅僅限于對(duì)網(wǎng)頁(yè)內(nèi)容的封裝,主進(jìn)程也添加了自定義的 API 來(lái)與用戶的作業(yè)系統(tǒng)進(jìn)行交互。 Electron 有著多種控制原生桌面功能的模塊,例如菜單、對(duì)話框以及托盤(pán)圖標(biāo)。
關(guān)于 Electron 主進(jìn)程模塊的完整列表,請(qǐng)參閱我們的 API 文檔。
每個(gè) Electron 應(yīng)用都會(huì)為每個(gè)打開(kāi)的 BrowserWindow
( 與每個(gè)網(wǎng)頁(yè)嵌入 ) 生成一個(gè)單獨(dú)的渲染器進(jìn)程。 洽如其名,渲染器負(fù)責(zé) 渲染 網(wǎng)頁(yè)內(nèi)容。 所以實(shí)際上,運(yùn)行于渲染器進(jìn)程中的代碼是須遵照網(wǎng)頁(yè)標(biāo)準(zhǔn)的 (至少就目前使用的 Chromium 而言是如此) 。
因此,一個(gè)瀏覽器窗口中的所有的用戶界面和應(yīng)用功能,都應(yīng)與您在網(wǎng)頁(yè)開(kāi)發(fā)上使用相同的工具和規(guī)范來(lái)進(jìn)行攥寫(xiě)。
雖然解釋每一個(gè)網(wǎng)頁(yè)規(guī)范超出了本指南的范圍,但您最起碼要知道的是:
<script>
? 元素可添加可執(zhí)行的 JavaScript 代碼。此外,這也意味著渲染器無(wú)權(quán)直接訪問(wèn) require
或其他 Node.js API。 為了在渲染器中直接包含 NPM 模塊,您必須使用與在 web 開(kāi)發(fā)時(shí)相同的打包工具 (例如 webpack
或 parcel
)
:::警告
為了方便開(kāi)發(fā),可以用完整的 Node.js 環(huán)境生成渲染器進(jìn)程。 在歷史上,這是默認(rèn)的,但由于安全原因,這一功能已被禁用。
:::
此刻,您或許會(huì)好奇:既然這些特性只能由主進(jìn)程訪問(wèn),那渲染器進(jìn)程用戶界面怎樣才能與 Node.js 和 Electron 的原生桌面功能進(jìn)行交互。 而事實(shí)上,確實(shí)沒(méi)有直接導(dǎo)入 Electron 內(nèi)容腳本的方法。
預(yù)加載(preload)腳本包含了那些執(zhí)行于渲染器進(jìn)程中,且先于網(wǎng)頁(yè)內(nèi)容開(kāi)始加載的代碼 。 這些腳本雖運(yùn)行于渲染器的環(huán)境中,卻因能訪問(wèn) Node.js API 而擁有了更多的權(quán)限。
預(yù)加載腳本可以在 BrowserWindow
構(gòu)造方法中的 webPreferences
選項(xiàng)里被附加到主進(jìn)程。
const { BrowserWindow } = require('electron')
//...
const win = new BrowserWindow({
webPreferences: {
preload: 'path/to/preload.js',
},
})
//...
因?yàn)轭A(yù)加載腳本與瀏覽器共享同一個(gè)全局 Window
接口,并且可以訪問(wèn) Node.js API,所以它通過(guò)在全局 window
中暴露任意 API 來(lái)增強(qiáng)渲染器,以便你的網(wǎng)頁(yè)內(nèi)容使用。
雖然預(yù)加載腳本與其所附著的渲染器在共享著一個(gè)全局 window
對(duì)象,但您并不能從中直接附加任何變動(dòng)到 window
之上,因?yàn)?nbsp;上下文隔離 是默認(rèn)的。
window.myAPI = {
desktop: true,
}
console.log(window.myAPI)
// => undefined
語(yǔ)境隔離(Context Isolation)意味著預(yù)加載腳本與渲染器的主要運(yùn)行環(huán)境是隔離開(kāi)來(lái)的,以避免泄漏任何具特權(quán)的 API 到您的網(wǎng)頁(yè)內(nèi)容代碼中。
取而代之,我們將使用 ?contextBridge
? 模塊來(lái)安全地實(shí)現(xiàn)交互:
const { contextBridge } = require('electron')
contextBridge.exposeInMainWorld('myAPI', {
desktop: true,
})
console.log(window.myAPI)
// => { desktop: true }
此功能對(duì)兩個(gè)主要目的來(lái)說(shuō)非常有用:
ipcRenderer
? 幫手模塊于渲染器中,您可以使用 進(jìn)程間通訊 ( inter-process communication, IPC ) 來(lái)從渲染器觸發(fā)主進(jìn)程任務(wù) ( 反之亦然 ) 。window
? 全局變量上添加自定義的屬性,好在 web 客戶端用上僅適用于桌面應(yīng)用的設(shè)計(jì)邏輯 。每個(gè) Electron 應(yīng)用程序都可以使用 UtilityProcess API 從主進(jìn)程生成多個(gè)子進(jìn)程。實(shí)用程序進(jìn)程在 Node.js 環(huán)境中運(yùn)行,這意味著它能夠要求模塊并使用所有 Node.js API。實(shí)用進(jìn)程可用于托管例如:不受信任的服務(wù)、CPU 密集型任務(wù)或容易崩潰的組件,這些組件以前托管在主進(jìn)程或使用 Node.js child_process.fork API 生成的進(jìn)程中。實(shí)用程序進(jìn)程與 Node.js child_process 模塊生成的進(jìn)程之間的主要區(qū)別在于,實(shí)用程序進(jìn)程可以使用 MessagePorts 與渲染器進(jìn)程建立通信通道。當(dāng)需要從主進(jìn)程中 fork 一個(gè)子進(jìn)程時(shí),Electron 應(yīng)用程序總是更喜歡 UtilityProcess API 而不是 Node.js child_process.fork API。
Copyright©2021 w3cschool編程獅|閩ICP備15016281號(hào)-3|閩公網(wǎng)安備35020302033924號(hào)
違法和不良信息舉報(bào)電話:173-0602-2364|舉報(bào)郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號(hào)
聯(lián)系方式:
更多建議: