electron開發(fā)入門(二)進程通信

目錄

  1. 主進程與渲染進程
  2. 主進程與渲染進程之間的通信

1. 主進程與渲染進程

在 electron 中续搀,最重要的一個概念就是主進程和渲染進程滴劲。

1.1 主進程

main.js在啟動應用后就創(chuàng)建了一個主進程-main process当宴,它可以通過electron中的一些模塊直接與原生GUI(在你的應用窗口)交互轰传。

1.2 渲染進程

僅啟動主進程并不能給你的應用創(chuàng)建應用窗口盗扒。窗口是通過main文件里的主進程調(diào)用叫BrowserWindow的模塊創(chuàng)建的纱昧。

上述示例中的index.html頁面刨啸,是主進程創(chuàng)建了一個渲染進程窗口所加載的Web頁面,每個頁面都是運行在自己的進程里识脆,這些進程我們稱之為渲染進程设联。

渲染進程會在窗口中渲染出web頁面(引用了CSS,JavaScript灼捂,圖片等的HTML文件)离例。web頁面是Chromium渲染的,因為各系統(tǒng)下標準是統(tǒng)一的的悉稠,所以兼容性很好宫蛆。

1.3 主進程與渲染進程的關(guān)系

主進程通過構(gòu)造BrowserWindow實例來創(chuàng)建頁面。每個 BrowserWindow實例都在自己的渲染進程里運行頁面的猛。當一個 BrowserWindow 實例被銷毀后洒扎,相應的渲染進程也會被終止辑甜。

主進程管理所有頁面和與之對應的渲染進程。每個渲染進程都是相互隔離的袍冷,并且只知道運行在該進程里的頁面。

在頁面里調(diào)用本地GUI是不允許的猫牡,因為在Web頁面里管理本地GUI資源是非常危險而且容易造成資源泄露胡诗。如果你想在網(wǎng)頁里進行GUI操作,該頁面的渲染進程必須與主進程進行通訊淌友,請求主進程進行相關(guān)的 GUI 操作煌恢。

2. 主進程與渲染進程之間的通信

在electron中,主進程與渲染進程有很多通信的方法震庭。比如ipcRenderer和ipcMain瑰抵,還可以在渲染進程使用remote模塊。

2.1 ipcMain & ipcRenderer

  • 主進程:ipcMain
  • 渲染進程:ipcRenderer

ipcMain模塊和ipcRenderer是類EventEmitter的實例器联。

在主進程中使用ipcMain接收渲染線程發(fā)送過來的異步或同步消息二汛,發(fā)送過來的消息將觸發(fā)事件。

在渲染進程中使用ipcRenderer向主進程發(fā)送同步或異步消息拨拓,也可以接收到主進程的消息肴颊。

  • 發(fā)送消息,事件名為 channel .
  • 回應同步消息, 你可以設(shè)置 event.returnValue .
  • 回應異步消息, 你可以使用 event.sender.send(...)

下面給出一個簡單例子:

// In main process.
const ipcMain = require('electron').ipcMain;
ipcMain.on('asynchronous-message', function(event, arg) {
console.log(arg); // prints "ping"
event.sender.send('asynchronous-reply', 'pong');
});
ipcMain.on('synchronous-message', function(event, arg) {
console.log(arg); // prints "ping"
event.returnValue = 'pong';
});

// In renderer process (web page).
const ipcRenderer = require('electron').ipcRenderer;
console.log(ipcRenderer.sendSync('synchronous-message', 'ping')); // prints "pong"
ipcRenderer.on('asynchronous-reply', function(event, arg) {
console.log(arg); // prints "pong"
});
ipcRenderer.send('asynchronous-message', 'ping');

同樣也可以從主進程向渲染進程發(fā)送消息渣磷,使用的是 webContents.send方法婿着,下面是具體的例子:

// 主進程.main.js
var window = null;
app.on('ready', function() {
window = new BrowserWindow({width: 800, height: 600});
window.loadURL('file://' + __dirname + '/index.html');
window.webContents.on('did-finish-load', function() {
window.webContents.send('ping', 'whoooooooh!');
});
});
<!-- index.html -->
<html>
<body>
<script>
require('electron').ipcRenderer.on('ping', function(event, message) {
console.log(message); // Prints "whoooooooh!"
});
</script>
</body>
</html>

2.2 remote模塊

remote模塊支持RPC風格的通信,在渲染進程中獲取主進程創(chuàng)建的一些全局對象和應用信息醋界,還可以調(diào)用主進程所提供的一些方法竟宋,如重啟應用、操作渲染進程等形纺。

remote 模塊提供了一種在渲染進程( 網(wǎng)頁) 和主進程之間進行進程間通訊( IPC) 的簡便途徑丘侠。使用remote 模塊,可以調(diào)用主進程對象的方法挡篓,而無需顯式地發(fā)送進程間消息婉陷,這類似于 Java
的 RMI。

下面是從渲染進程創(chuàng)建一個瀏覽器窗口的例子:

const remote = require('electron').remote;
const BrowserWindow = remote.BrowserWindow;
var win = new BrowserWindow({ width: 800, height: 600 });
win.loadURL('https://github.com');

注意: 反向操作( 從主進程訪問渲染進程) 官研,可以使用webContents.executeJavascript.

遠程對象

remote 模塊返回的每個對象( 包括函數(shù)) 都代表了主進程中的一個對象(我們稱之為遠程對象或者遠程函數(shù))秽澳。當調(diào)用遠程對象的方法、執(zhí)行遠程函數(shù)或者使用遠程構(gòu)造器( 函數(shù)) 創(chuàng)建新對象時戏羽,其實就是在發(fā)送同步的進程間消息担神。

在上面的例子中, BrowserWindow 和 win 都是遠程對象始花,然而 new BrowserWindow 并沒有在渲染進程中創(chuàng)建 BrowserWindow 對象妄讯。 而是在主進程中創(chuàng)建了BrowserWindow 對象孩锡,并在渲染進程中返回了對應的遠程對象,即 win 對象亥贸。

請注意只有可枚舉屬性才能通過 remote 進行訪問.

遠程對象的生命周期

Electron 確保在渲染進程中的遠程對象存在(換句話說躬窜,沒有被垃圾收集),那主進程中的對應對象也不會被釋放炕置。當遠程對象被垃圾收集之后荣挨,主進程中的對應對象才會被取消關(guān)聯(lián)。如果遠程對象在渲染進程泄露了(即朴摊,存在某個表中但永遠不會釋放)默垄,那么主進程中的對應對象也一樣會泄露,所以你必須小心不要泄露了遠程對象甚纲。

不過口锭,主要的值類型如字符串和數(shù)字,是傳遞的副本介杆。

給主進程傳遞回調(diào)函數(shù)

在主進程中的代碼可以從渲染進程——remote模塊——中接受回調(diào)函數(shù)鹃操,但是使用這個功能的時候必須非常非常小心。

首先这溅,為了避免死鎖组民,傳遞給主進程的回調(diào)函數(shù)會進行異步調(diào)用。所以不能期望主進程來獲得傳遞過去的回調(diào)函數(shù)的返回值悲靴。

比如臭胜,你不能主進程中給 Array.map 傳遞來自渲染進程的函數(shù)。

// 主進程 mapNumbers.js
exports.withRendererCallback = function(mapper) {
    return [1,2,3].map(mapper);
} 

exports.withLocalCallback = function() {
    return exports.mapNumbers(function(x) {
        return x + 1;
    });
} 

// 渲染進程
var mapNumbers = require("remote").require("./mapNumbers");

var withRendererCb = mapNumbers.withRendererCallback(function(x) {
    return x + 1;
})

var withLocalCb = mapNumbers.withLocalCallback()

console.log(withRendererCb, withLocalCb) // [true, true, true], [2, 3, 4]

如你所見癞尚,渲染器回調(diào)函數(shù)的同步返回值沒有按預期產(chǎn)生耸三,與主進程中的一模一樣的回調(diào)函
數(shù)的返回值不同。

其次浇揩,傳遞給主進程的函數(shù)會持續(xù)到主進程對他們進行垃圾回收仪壮。

例如,下面的代碼第一眼看上去毫無問題胳徽。給遠程對象的 close 事件綁定了一個回調(diào)函數(shù):

remote.getCurrentWindow().on('close', function() {
// blabla...
});

但記住主進程會一直保持對這個回調(diào)函數(shù)的引用积锅,除非明確的卸載它。如果不卸載养盗,每次重新載入窗口都會再次綁定缚陷,這樣每次重啟就會泄露一個回調(diào)函數(shù)。

更嚴重的是往核,由于前面安裝了回調(diào)函數(shù)的上下文已經(jīng)被釋放箫爷,所以當主進程的 close 事件觸
發(fā)的時候,會拋出異常。

為了避免這個問題虎锚,要確保對傳遞給主進程的渲染器的回調(diào)函數(shù)進行清理硫痰。可以清理事件處
理器窜护,或者明確告訴主進行取消來自已經(jīng)退出的渲染器進程中的回調(diào)函數(shù)效斑。

訪問主進程中的內(nèi)置模塊

在主進程中的內(nèi)置模塊已經(jīng)被添加為 remote 模塊中的屬性,所以可以直接像使
用 electron 模塊一樣直接使用它們柱徙。

const app = remote.app;

方法

remote 模塊有以下方法:

  • remote.require(module)
    module String
    返回在主進程中執(zhí)行 require(module) 所返回的對象鳍悠。
  • remote.getCurrentWindow()
    返回該網(wǎng)頁所屬的 BrowserWindow 對象。
  • remote.getCurrentWebContents()
    返回該網(wǎng)頁的 WebContents 對象
  • remote.getGlobal(name)
    name String
    返回在主進程中名為 name 的全局變量(即 global[name] ) 坐搔。
  • remote.process
    返回主進程中的 process 對象。等同于 remote.getGlobal('process') 但是有緩存
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末敬矩,一起剝皮案震驚了整個濱河市概行,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌弧岳,老刑警劉巖凳忙,帶你破解...
    沈念sama閱讀 222,946評論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異禽炬,居然都是意外死亡涧卵,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,336評論 3 399
  • 文/潘曉璐 我一進店門腹尖,熙熙樓的掌柜王于貴愁眉苦臉地迎上來柳恐,“玉大人,你說我怎么就攤上這事热幔±稚瑁” “怎么了?”我有些...
    開封第一講書人閱讀 169,716評論 0 364
  • 文/不壞的土叔 我叫張陵绎巨,是天一觀的道長近尚。 經(jīng)常有香客問我,道長场勤,這世上最難降的妖魔是什么戈锻? 我笑而不...
    開封第一講書人閱讀 60,222評論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮和媳,結(jié)果婚禮上格遭,老公的妹妹穿的比我還像新娘。我一直安慰自己窗价,他們只是感情好如庭,可當我...
    茶點故事閱讀 69,223評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般坪它。 火紅的嫁衣襯著肌膚如雪骤竹。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,807評論 1 314
  • 那天往毡,我揣著相機與錄音蒙揣,去河邊找鬼。 笑死开瞭,一個胖子當著我的面吹牛懒震,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播嗤详,決...
    沈念sama閱讀 41,235評論 3 424
  • 文/蒼蘭香墨 我猛地睜開眼个扰,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了葱色?” 一聲冷哼從身側(cè)響起递宅,我...
    開封第一講書人閱讀 40,189評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎苍狰,沒想到半個月后办龄,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,712評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡淋昭,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,775評論 3 343
  • 正文 我和宋清朗相戀三年俐填,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片翔忽。...
    茶點故事閱讀 40,926評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡英融,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出呀打,到底是詐尸還是另有隱情矢赁,我是刑警寧澤,帶...
    沈念sama閱讀 36,580評論 5 351
  • 正文 年R本政府宣布贬丛,位于F島的核電站撩银,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏豺憔。R本人自食惡果不足惜额获,卻給世界環(huán)境...
    茶點故事閱讀 42,259評論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望恭应。 院中可真熱鬧抄邀,春花似錦、人聲如沸昼榛。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,750評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至奥喻,卻和暖如春偶宫,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背环鲤。 一陣腳步聲響...
    開封第一講書人閱讀 33,867評論 1 274
  • 我被黑心中介騙來泰國打工纯趋, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人冷离。 一個月前我還...
    沈念sama閱讀 49,368評論 3 379
  • 正文 我出身青樓吵冒,卻偏偏與公主長得像,于是被迫代替她去往敵國和親西剥。 傳聞我的和親對象是個殘疾皇子痹栖,可洞房花燭夜當晚...
    茶點故事閱讀 45,930評論 2 361

推薦閱讀更多精彩內(nèi)容