Electron系列文章-主程式與渲染程式

蘇格團隊發表於2019-03-19

本文主要講解上一章節提到的主程式與渲染程式的概念,以及它們是如何被使用的

如果對文章的內容有任何疑問或吐槽,請直接在下方評論,大家共同學習和改進

閱讀時間:約4min

主程式與渲染程式

我們來回顧一下,程式目錄結構章節中所給出的基本目錄結構

app----------------------------應用程式程式碼目錄
├─main.js----------------------程式啟動入口,主程式
├─common-----------------------通用模組
├─log--------------------------日誌模組
├─config-----------------------配置模組
├─ipc--------------------------程式間模組
├─appNetwork-------------------應用通訊模組
└─browserWindows---------------視窗管理,渲染程式
    ├─components---------------通用元件模組
    ├─store--------------------資料共享模組
    ├─statics------------------靜態資源模組
    └─src----------------------視窗業務模組
        ├─視窗A----------------視窗
        └─視窗B----------------視窗
複製程式碼

在上面的目錄結構中,main.js就是我們所說的主程式。而通過browserWindows目錄下視窗檔案建立的程式,我們稱之為渲染程式。渲染程式需要通過主程式來建立,並被主程式所管理。這裡大家可能會有疑問了,什麼是程式?為什麼要分主程式和渲染程式呢?

程式的概念

計算機程式相關的知識在搜尋引擎中可以搜到很多,我們這裡不做過多的講解。讀者可以把程式理解為作業系統管理應用程式的基本單位,每個程式之間的資源是不能直接共享的。開啟作業系統的工作管理員,我們可以看到當前作業系統都有那些程式,如下圖

Electron系列文章-主程式與渲染程式

主程式

回顧以往的web開發,我們的程式碼,無論是HTML、CSS還是Javascript,都是執行在瀏覽器的沙盒中的,我們無法越過瀏覽器的許可權訪問系統本身的資源,程式碼的能力被限制在了瀏覽器中。瀏覽器之所以這麼做,是為了安全的考慮。設想一下,我們在使用瀏覽器的時候,會開啟各式各樣不同來源的網站,如果JavaScript程式碼有能力訪問並操作本地作業系統的資源,那將是多麼可怕的事情。你在某天不小心開啟了一個惡意的網站,可能你儲存在硬碟上的檔案就被偷走了(都用不著去修電腦)。

但我們要開發的是桌面應用程式,如果無法訪問到本地的資源肯定是不行的。Electron將nodejs巧妙的融合了進來,讓nodejs作為整個程式的管家。管家擁有較高的許可權,可以訪問和操作本地資源,使用原本在瀏覽器中不提供的高階API。同時管家也管理著渲染程式視窗的建立和銷燬。所以,我們將這個管家稱之為主程式。在使用Electron開發的程式中,會使用main.js作為程式的主入口,該檔案內程式碼執行的內容,就是主程式中執行的內容。

下面我們一起來看看主程式中一般都做些什麼。

//main.js

var electron      = require('electron');
var app           = require('electron').app;

//初始化
app.on('ready', function(){

    try{      
        //app ready
    }catch(err){
        log.error(err);
    }
});

複製程式碼

上面是一個最簡單的main.js例子。在例子中,我們首先引入了electronelectron.app模組。electron.app物件控制著整個程式的生命週期,在這我們只註冊了生命週期中的ready事件,當ready事件被觸發的時候,表示整個程式已經初始化完畢,可以開始進行建立視窗等業務邏輯了。

在現實的應用中,主程式的程式碼遠比上面的例子複雜的多。有許多需求特性的實現都是在主程式中完成,下面舉個例子進行講解。

程式互斥

在某些場景中,應用程式被要求在系統中只能同時開啟一個。所以當某個應該已經在系統中執行時,如果再次雙擊應用icon,程式應該將自己退掉,或者是把之前開啟的程式退掉。

(function(){

  app.makeSingleInstance(singleInstanceCallBack);

  function singleInstanceCallBack(commandLine, workingDirectory){

    console.log('command line: ', commandLine);
    console.log('working directory: ', workingDirectory);

    app.exit(0);        
  }
})();

複製程式碼

這裡使用的是app.makeSingleInstanceapi實現的這個功能。singleInstanceCallBack函式是當第二個例項啟動時,第一個例項執行的回撥,所以singleInstanceCallBack裡面使用的app實際上指向的是先開啟的例項(剛接觸這個api的時候確實有點繞),上面的程式碼中,singleInstanceCallBack執行時,呼叫了app.exit方法退出了先開啟的程式。那我們如何去判斷當前是第二個例項呢?其實,makeSingleInstance的返回值是一個boolean型別的值,為true時表示當前是第二個例項。如果需求是想讓第二個例項退出,則在當前的作用域中直接呼叫app.exit即可。

渲染程式

Electron整合了Chromium來展示視窗介面,視窗中所看到的內容使用的都是HTML渲染出來的。 Chromium本身是多程式渲染頁面的架構(在預設情況下,Chromium的預設策略是對每一個tab新開一個程式,以確保每個頁面是獨立且互不影響的。避免一個頁面的崩潰導致全部頁面無法使用),所以Electron在展示視窗時,也會使用到Chromium的多程式架構。而這種多程式渲染架構在Electron中,就被稱之為渲染程式(render process)。

在Electron中,每建立一個新的視窗,都是一個獨立的程式。

//main.js
const {BrowserWindow} = require('electron');
const window1 = new BrowserWindow({width: 200, height: 200})
const window2 = new BrowserWindow({width: 200, height: 200})

window1.loadURL('https://baidu.com');
window2.loadURL(`file://${__dirname}/index.html`)

複製程式碼

在上面的程式碼中,我們建立了2個視窗,window1window2。這兩個視窗就是互相獨立的程式。window1視窗內容指向的是百度首頁,window2視窗內容指向的是我們自己開發的html頁面。在index.html中,我們可以像開發正常的web網頁一樣,開發視窗內容。以下是index.html的一個示例

<!DOCTYPE html>
<html lang="zh-cn">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1,user-scalable=0">
    <title>main page</title>
</head>
<body>
    <div id="app">Hello World</div>
    <script type="text/javascript" src="mainPage.js"></script>
</body>
</html>
複製程式碼

在介紹主程式的篇幅中,我們說到只有主程式才有獲取本地資源的許可權。實際場景中,有時需要將主程式中獲取的本地資料在視窗中展示出來,該怎麼實現呢?

在下一章,我們會重點講解主程式與渲染程式之間如何通訊的知識。

相關文章