摘要:為了能使不同的進程互相訪問資源并進行協調工作,才有了進程間通信。此時,就需要與渲染進程通信了。發消息,渲染進程收消息內部使用來發消息。
前言作者:鐘離,酷家樂PC客戶端負責人
原文地址:https://webfe.kujiale.com/electron-ku-jia-le-ke-hu-duan-kai-fa-shi-jian-fen-xiang-jin-cheng-tong-xin/
酷家樂客戶端:下載地址 https://www.kujiale.com/activity/136
文章背景:在酷家樂客戶端在V12改版成功后,我們積累了許多的寶貴的經驗和最佳實踐。前端社區里關于Electron知識相對較少,因此希望將這些內容以系列文章的形式分享出來。
系列文章:【Electron】酷家樂客戶端開發實踐分享 — 入坑篇
【Electron】酷家樂客戶端開發實踐分享 — 軟件自動更新
【Electron】酷家樂客戶端開發實踐分享 — 瀏覽器啟動客戶端
【Electron】酷家樂客戶端開發實踐分享 — 進程通信
【Electron】酷家樂客戶端開發實踐分享 — 下載管理器
不定期更新...
Electron中的進程,其實就是計算機中的進程,我們先來看看什么是進程通信
進程間通信(IPC,Inter-Process Communication),指至少兩個進程或線程間傳送數據或信號的一些技術或方法
每個進程都有自己的一部分獨立的系統資源,彼此是隔離的。為了能使不同的進程互相訪問資源并進行協調工作,才有了進程間通信。
一個Electron應用有一個主進程和多個渲染進程,渲染進程還可能內嵌多個webview。兩兩之間都可能需要進行通信,情況還是比較復雜的。
需要通信的對象主進程: 使用ipcMain進行通信
渲染進程: 使用ipcRenderer和remote模塊進行通信
webview: 一般會禁用webview的node集成,然后使用preload的方式拿到ipcRenderer來做進程通信。
// preload.js const electron = require("electron"); const { ipcRenderer } = electron; // 把ipcRenderer掛載到window上,webview內部的js可以拿到這個模塊 window.ElectronIpcRenderer = ipcRenderer;ipcRenderer/ipcMain VS remote
主進程和渲染進程通信方式,擰出來多帶帶說一下。先來看一個簡單例子的:
點擊創建按鈕,創建一個新的窗口。點擊關閉按鈕,關掉這個新窗口。
左側代碼使用ipcRenderer/ipcMain進行通信,右側代碼使用remote進行通信。實現的功能都是一樣的。從這個例子中可以發現:
使用ipcMain/ipcRenderer通信,業務邏輯同時存在于主進程和渲染進程的代碼中。同時為了通信,會產生非常多的event & event handler。
使用remote通信,渲染進程直接獲取主進程模塊。而且,使用remote通信不需要使用事件和回調函數,寫出來的代碼清晰直觀。
主進程可以視作為模塊提供者,而渲染進程是模塊的消費者,渲染進程通過remote來獲取主進程的模塊,實現業務邏輯。這樣做有以下好處:
主進程/渲染進程代碼解耦,職責分明,提升可維護性
業務邏輯內聚在渲染進程
減少主進程/渲染進程冗余無用的代碼
具體實現介紹了一下前置知識,現在來看看不同情況下,Electron進程通信的實現方法。
主進程和渲染進程通信主進程發消息、渲染進程收消息:主進程使用窗口的webContents發消息,渲染進程內使用ipcRenderer收消息
// main.js const win = new BrowserWindow(); win.load("index.html"); win.webContents.send("hello", {a: 1}); // index.html 中的js const { ipcRenderer } = require("electron"); ipcRenderer.on("hello", (e, data) => { console.log(data); // 打印出 {a: 1} })
渲染進程發消息、主進程收消息: 渲染進程使用ipcRenderer發消息,主進程使用ipcMain收消息。
// main.js const { ipcMain } = require("electron"); ipcMain.on("hello", (e, data) => { console.log(data); // 打印出 {a: 1} }); // index.html 中的js const { ipcRenderer } = require("electron"); ipcRenderer.send("hello", {a: 1});
一般遇到主進程和渲染進程通信的情況,大部分都是渲染進程來需要獲取主進程的模塊,此時推薦使用remote來做通信。
// main.js // 主進程無需添加任何代碼 // index.html 中的js,獲取主進程模塊 const { remote } = require("electron"); const {app, BrowserWindow, dialog, ...} = remote;渲染進程與渲染進程通信
渲染進程之間也是會頻繁通信的,具體場景舉例:在設置窗口點擊更換皮膚,需要通知所有窗口進行顏色、背景的更新。
最佳實踐:渲染進程A通過remote模塊,獲取到需要目標窗口的webContents對象,然后通過webContents向目標窗口的發送消息。目標窗口使用ipcRenderer監聽事件。
const { remote } = require("electron") const allWindows = remote.BrowserWindow.getAllWindows(); // 窗口A中的邏輯 // 1、第一步,獲取到目標窗口的webContents // 可以根據id,title來找到目標窗口,也可以用其他辦法 const targetId = 1; const targetTitle = "目標窗口"; // let targetWindow = allWindows.find(w => w.id === targetId); let targetWindow = allWindows.find(w => w.title === targetTitle); // 2、第二步,使用目標窗口的webContents發送消息 targetWindow.webContents.send("theme-change", "gray"); // 目標窗口內的邏輯,使用ipcRenderer監聽事件 // 窗口收到theme-change事件,改變窗口顏色。不需要關注事件從哪里發出,只需要關注接收到該事件后做什么 ipcRenderer.on("theme-change", (e, theme) => { console.log(theme); // gray });
還有一種傳統的辦法,不用remote,改用ipcMain做通信,但是會在主進程冗余很多事件代碼。因此還是推薦使用remote,理由同上。小例子:
// mian.js // 用于事件轉發,沒有實際的邏輯 ipcMain.on("send-event-to-window", (e, id, eventName, ...args) => { BrowserWindow.getAllWindows() .find(w = > w.id === id) .webContents .send(eventName, ...args); }); // 窗口A內部,向主進程發事件 const targetId = 1; ipcRenderer.send("send-event-to-window", id, "theme-change", "gray"); // 目標窗口 ipcRenderer.on("theme-change", (e, theme) => { console.log(theme); // gray });webview與渲染進程通信
內嵌的web頁面運行在客戶端中,也可以獲取本地化的能力。此時,webview就需要與渲染進程通信了。
在文章開頭講到了,為了應用的安全性webview是需要禁用node集成的,通過preload的方式,注入了一個ipcRenderer并掛載到window上。
webview發消息,渲染進程收消息:webview內部使用ipcRenderer.sendToHost來發消息。渲染進程獲取到webview的dom元素,監聽dom元素的ipc-message事件接收消息
// 渲染進程拿到webview的dom,接收事件 const webview = document.querySelector("webview") webview.addEventListener("ipc-message", (event) => { console.log(event.channel); // hello }); // webview頁面內,假裝點了一個按鈕,發送事件 btn.onclick = () => { window.ElectronIpcRenderer.sendToHost("hello") }
渲染進程發消息,webview收消息:渲染進程使用webview.send發消息。webview使用內置的ipcRenderer收消息。
// webview內部 window.ElectronIpcRenderer.on("event-from-renderer", (e, data) => { console.log(e, data); // {a: 1} }); // 渲染進程內部 const webview = document.querySelector("webview") webview.send("event-from-renderer", {a: 1})總結
這三種通信方式是最基礎的,在此之上進行排列組合也是很常見的,這個由開發者自行拓展即可。
舉一個小例子:webview內部觸發更換皮膚功能 -> 通知渲染進程同步更新皮膚 -> 渲染進程收到消息,向其他渲染進程通信 -> 同步更新皮膚完成。
最后歡迎大家在評論區討論,技術交流 & 內推 -> zhongli@qunhemail.com
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/104682.html
摘要:為了能使不同的進程互相訪問資源并進行協調工作,才有了進程間通信。此時,就需要與渲染進程通信了。發消息,渲染進程收消息內部使用來發消息。 作者:鐘離,酷家樂PC客戶端負責人原文地址:https://webfe.kujiale.com/electron-ku-jia-le-ke-hu-duan-kai-fa-shi-jian-fen-xiang-jin-cheng-tong-xin/酷家...
摘要:為了能使不同的進程互相訪問資源并進行協調工作,才有了進程間通信。此時,就需要與渲染進程通信了。發消息,渲染進程收消息內部使用來發消息。 作者:鐘離,酷家樂PC客戶端負責人原文地址:https://webfe.kujiale.com/electron-ku-jia-le-ke-hu-duan-kai-fa-shi-jian-fen-xiang-jin-cheng-tong-xin/酷家...
摘要:系列文章酷家樂客戶端開發實踐分享入坑篇酷家樂客戶端開發實踐分享軟件自動更新酷家樂客戶端開發實踐分享瀏覽器啟動客戶端酷家樂客戶端開發實踐分享進程通信酷家樂客戶端開發實踐分享下載管理器不定期更新本文的初衷所使用的技術棧和前端工程師完美契合。 作者:鐘離,酷家樂PC客戶端負責人原文地址:https://webfe.kujiale.com/electron-ku-jia-le-ke-hu-d...
摘要:系列文章酷家樂客戶端開發實踐分享入坑篇酷家樂客戶端開發實踐分享軟件自動更新酷家樂客戶端開發實踐分享瀏覽器啟動客戶端酷家樂客戶端開發實踐分享進程通信酷家樂客戶端開發實踐分享下載管理器不定期更新本文的初衷所使用的技術棧和前端工程師完美契合。 作者:鐘離,酷家樂PC客戶端負責人原文地址:https://webfe.kujiale.com/electron-ku-jia-le-ke-hu-d...
摘要:作者鐘離,酷家樂客戶端負責人原文地址酷家樂客戶端下載地址文章背景在酷家樂客戶端在改版成功后,我們積累了許多的寶貴的經驗和最佳實踐。用戶在電腦上安裝客戶端,實際上會將客戶端代碼文件持久儲存到本機。通常我們會在軟件啟動時檢查更新。 作者:鐘離,酷家樂PC客戶端負責人原文地址:https://webfe.kujiale.com/electron-autoupdate/酷家樂客戶端:下載地址...
閱讀 3024·2021-09-22 15:52
閱讀 2903·2019-08-30 15:55
閱讀 2699·2019-08-30 15:53
閱讀 2453·2019-08-30 13:21
閱讀 1620·2019-08-30 13:10
閱讀 2481·2019-08-26 12:09
閱讀 2563·2019-08-26 10:33
閱讀 1802·2019-08-23 18:06