阅读 302

关于 Electron 进程间通信的一个小小实践

Electron 是一个跨平台桌面框架,它集成了 node.js 和 chromium,所以我们可以借助 node.js 实现桌面客户端访问操作系统资源的功能(出于安全,浏览器是不可以访问操作系统的),而 chromium 允许我们使用前端工具HTML、JS、CSS 甚至结合 React、Vue 等渲染出用户界面。

用进程间通信模拟实现 B/S 架构

B/S 即 ‘浏览器/服务器’ 架构。既然 Electron 由 node.js 和 chromium 集成, 把 Electron 的渲染进程直接当作客户端浏览器进程,主进程当作服务器进程,把访问操作系统资源、读写文件等都放在主进程里,而渲染进程专心用于渲染页面和向主进程‘请求’操作资源,主进程和渲染进程之间可以实现进程间通信,可以模拟浏览器和服务器之间的 ajax 请求。

一个结合 Electron 的项目架构:

下面以一个获取 github 用户信息和远程仓库的 Electron APP 为例,用具体的代码来展示如何实现

渲染进程里使用 ipcRenderer 封装一个类 api 请求:

// render/api.js

var electron = window.electron
var { ipcRenderer } = electron
import ipc_channel from '../const/ipc_channel'

export default {
  loginGithub: ({username, password, cb}) => { // 登录 github 以创建一个 token
  // 向主进程请求登录 GitHub
    ipcRenderer.send(ipc_channel.LOGIN_GITHUB, {username, password})

 // 主进程完成登录后返回登录响应(比如一个token)
    ipcRenderer.on(ipc_channel.LOGIN_GITHUB, (e, res) => {
      cb(res)
    })
  },
  logoutGithub: ({username, password, id, cb}) => { // 退出登录
    ipcRenderer.send(ipc_channel.LOGOUT_GITHUB, {username, password, id})

    ipcRenderer.on(ipc_channel.LOGOUT_GITHUB, (e, res) => {
      cb(res)
    })
  } 
}
复制代码

主进程使用 ipcMain 将渲染进程的各个请求路由到相应的路由处理器,并且传递一个回调函数方便路由处理器向渲染进程发送响应:

//main.js

const routes = require('./server-routes/routes')

for(let routeName in routes) {
  ipcMain.on(routeName, (e, params) => {// 监听渲染进程各个 ‘请求’
    routes[routeName]({ // 路由
      params, // 请求参数
      cb: (respond) => {// 回调函数用于向渲染进程发送响应
        e.sender.send(routeName, respond)}
      })
    })
}

复制代码

路由处理器:

// server-routes/routes.js

var github = require('octonode')// octonode 是一个 GitHub API 封装库
var ipc_channel = require('../../const/ipc_channel')
const fs = require('fs')

const {getABranchContent, readLocalDir_OR_FileWithPath, readAFile} = require('./middleweres')

module.exports = {
  [ipc_channel.LOGIN_GITHUB]: ({params, cb}) => {
    let {username, password} = params

    var scopes = {
      'scopes': ['user', 'repo', 'gist'],
      'note': 'admin script'
    }
    
    github.auth.config({
      username,
      password
    }).login(scopes, function (err, id, token, headers) {
      console.log(id, token)
      if(!err) cb({id, token})
    })
  },

  [ipc_channel.LOGOUT_GITHUB]: ({params, cb}) => {
    let {username, password, id} = params

    github.auth.config({
      username,
      password
    }).revoke(id, function (err) {
      if (err) throw err
      else cb({msg: '已经退出登录'})
    })
  }
}
复制代码

用一个单独的文件导出各个 ipc channel:

// ipc_channel.js

module.exports = {
    LOGIN_GITHUB: 'login-github-for-token', // 登录 GitHub 以获取 token
    LOGOUT_GITHUB: 'logout-and-revoke-token', // 退出登录并销毁 token
    GET_REPO: 'get-a-repo', // 获取 github 上某个仓库的内容
    READ_LOCAL_PATH: 'read-local-path', // 读取本地目录
    READ_LOCAL_FILE: 'read-local-file', // 读取本地文件
    READ_LOCAL_REPO_INFO_FILE: 'read-repo-info-file' // 读取存储在本地的仓库的信息
}
复制代码

这样借鉴了 web 中前后端分离的思想,个人认为可以很清晰的分离应用的逻辑。

本文的素材源自个人的 Electron 小项目:github-repo-viewer

关注下面的标签,发现更多相似文章
评论