Electron remote 模塊

2019-08-14 19:21 更新

remote 模塊提供了一種在渲染進程(網(wǎng)頁)和主進程之間進行進程間通訊(IPC)的簡便途徑。

Electron中, 與GUI相關(guān)的模塊(如 dialog, menu 等)只存在于主進程,而不在渲染進程中 。為了能從渲染進程中使用它們,需要用ipc模塊來給主進程發(fā)送進程間消息。使用 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)。

如果遠程對象在渲染進程泄露了(即,存在某個表中但永遠不會釋放),那么主進程中的對應對象也一樣會泄露, 所以你必須小心不要泄露了遠程對象。If the remote object is leaked in the renderer process (e.g. stored in a map but never freed), the corresponding object in the main process will also be leaked, so you should be very careful not to leak remote objects.

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

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

在主進程中的代碼可以從渲染進程——remote模塊——中接受回調(diào)函數(shù),但是使用這個功能的時候必須非常非常小心。Code in the main process can accept callbacks from the renderer - for instance the remotemodule - but you should be extremely careful when using this feature.

首先,為了避免死鎖,傳遞給主進程的回調(diào)函數(shù)會進行異步調(diào)用。所以不能期望主進程來獲得傳遞過去的回調(diào)函數(shù)的返回值。First, in order to avoid deadlocks, the callbacks passed to the main process are called asynchronously. You should not expect the main process to get the return value of the passed callbacks.

比如,你不能主進程中給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') 但是有緩存。

以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號