前言碎语

此想法是在使用 electron 进程间通信(IPC)过程中,无法忍受其 API 的使用不友好性而产生。

为了提高代码可读性、可维护性,而不得已造轮子了。

生命在于折腾,其乐无穷。

Electron 中 IPC 的通信方式

在 Electron 中分为两个进程:

  1. Main Process(主进程)。是 Node.js 跑的一个进程,可以调用 Node API 和 Electron 封装好的 API。
  2. Renderer Process(渲染进程)。是运行在 Chromium 中的 web 进程。

因为 Electron 出于安全考虑,渲染进程的 API 是有限制的。因为 web 端可能会加载第三方 js 代码,不可能让第三方为所欲为的。

假如在一些场景中我可能要获取某个文件夹下的文件列表(举例而已),在 Node 中使用 fs 模块即可完成,但是在 web 端无法使用 fs API。

这时候就需要使用 IPC 进程通信来解决。

就像是 nodejs 中的子进程一样
通过 spawn 方法开启一个子进程,两个进程之间只能通过 IPC 协议通信

主进程:

import { IpcMain } from 'electron'
import fs from 'fs'// 监听渲染进程发来的 getDir 请求
IpcMain.on('getDir', (event, data) => {fs.readdir('path', (err, files) => {if (err) {// 响应渲染进程获取失败了event.reply('dir-result', 'err')} else {const result = files.map(/* do something */)// 响应渲染进程获取到的结果event.reply('dir-result', result)}})
})

渲染进程:

const { ipcRenderer } = require('electron')// 先监听主进程发来的消息
ipcRenderer.on('dir-result', (event, data) => {// do something
})// 发送给主进程
ipcRenderer.send('getDir', '/Users')

代码很简单,主进程先监听渲染进程消息,渲染进程再监听主进程消息,然后渲染进程发起消息。

很好理解,只不过渲染进程的操作过于繁琐

假如此逻辑放入vue 组件中,那么需要在 created 中进行监听主进程消息,在 destroyed 中进行解绑改事件。

那么怎么去优化此处的体验呢?造轮子呗~

对 IPC 通信方式进行二次封装

先看下面这段代码:

此处为渲染进程部分代码,以 React 组件举例。

// 渲染进程
import React, { useState, useEffect } from 'react'
import request from './request'export default function IpcTest () {const [list, setList] = useState([])useEffect(() => {init()}, [])// 进行初始化操作const init = async () => {// request 取代 ipcRenderer.send 和 ipcRenderer.onconst result = await request('test', { a: 1 })// result => ['1', '2', '3'] from Main ProcesssetList(result)}
}// 主进程
import server from './server'
// 类似 koa-router 的使用方式
server.use('test', async (ctx, data) => {// data => { a: 1 }  from Renderer Processconst result = await doSomething(data)ctx.reply(['1', '2', '3'])
})

上面代码以 http 请求的写法来处理了 IPC 通信。其中 requestserver 则是进行二次封装后的轮子。

这样使用 async/await 的方式来处理,是不是就轻松多了?代码的可读性、可维护性也增强了。

而且在封装的过程中完全可以按照 axios 的 API 来处理,便于代码迁移(当然这里业务逻辑的通用性另说)。

废话不多说下面来看一下处理原理。

Electron IPC 异步封装

request 大致实现逻辑:

const { ipcRenderer } = require('electron')const _map = new Map()ipcRenderer.on('from-server', (event, params) => {const cb = _map.get(params.symbol)if (typeof cb === 'function') {_map.delete(params.symbol)cb()}
})export default request (type, data) {const _symbol = Date.now() + typereturn new Promise(resolve => {_map.set(_symbol, data => {resolve(data)})ipcRenderer.send('from-type', {_symbol, type, data})})
}

server 大致实现逻辑:

import { ipcMain } from 'electron'const _map = new Map()ipcMain.on('from-client', (event, params) => {const reply = function (data) {event.reply('from-server', {_symbol: params._symbol,// data 传递给客户端,最终 resolve 它data})}const ctx = {reply,type: params.type}const cb = _map.get(params.type)if (typeof cb === 'function') {cb(ctx, params.data)} else {// 没有注册~}
})export default function use (type, callback) {_map.set(type, cb)
}

一个简单基础版的 IPC 封装就完成了,在此功能上还可以增加一些 timeout多次调用只获取最后一次返回的数据类似的功能,这些在原生的 electron IPC API 上是无法实现的(也可能是我文档看的少没有发现)。

测试

起初在做单元测试时,走了弯路。

因为 IPC 是两个进程之间交互的一个过程,当时一直在想如何简单的启动一个 electron 容器进行测试。

后来又根据官网介绍想通过 Node 启动两个进程来模拟 IPC 交互过程,这其实也是个弯路。

其实需要做的只要保证 use、request 方法能跑通、保证内部逻辑运行正确即可。

最后直接模拟了 ipcRenderer (on 和 send)、ipcMain (on 和 reply),将这 4 个方法的输入与输出与 electron 提供的 API 表现一致即可达到目的。

类似于 测试驱动 模拟一个测试环境可以让代码正常运行,且表现一致。

async function_Electron IPC 通信如何使用 async/await 调用?相关推荐

  1. 【-Flutter/Dart 语法补遗-】 sync* 和 async* 、yield 和yield* 、async 和 await

    前言 类别 关键字 返回类型 搭档 多元素同步 sync* Iterable<T> yield.yield* 单元素异步 async Future<T> await 多元素异步 ...

  2. ttf_openfont可以多次调用吗_【译文】Rust futures: async fn中的thread::sleep和阻塞调用...

    原文:Rust futures: thread::sleep and blocking calls inside async fn URL: https://blog.hwc.io/posts/rus ...

  3. Rust futures: async fn 中的 thread::sleep 和阻塞调用

    原文:Rust futures: thread::sleep and blocking calls inside async fn URL: https://blog.hwc.io/posts/rus ...

  4. 传统的Linux中IPC通信原理

    在了解 Binder 跨进程通信原理之前, 我们先了解一下 Linux 传统的进程间通信的概念和基本原理, 这样有助于我们更好的理解 Binder 的通信原理. 这个部分基本都是理论, 基础不是很好的 ...

  5. 4月25日 python学习总结 互斥锁 IPC通信 和 生产者消费者模型

    一.守护进程 import random import time from multiprocessing import Processdef task():print('name: egon')ti ...

  6. web前端培训分享Electron之IPC 通信

    本文由小千给大家分享Electron之IPC 通信. 1.index.html <!DOCTYPE html><html><head><meta charse ...

  7. web前端技术分享Electron之IPC 通信

    本文由小千给大家分享Electron之IPC 通信. 1.index.html <!DOCTYPE html><html><head><meta charse ...

  8. IPC通信:Posix消息队列的属性设置

    IPC通信:Posix消息队列的属性设置 Posix消息队列的属性使用如下结构存放: struct mq_attr { long mq_flags; /*阻塞标志位,0为非阻塞(O_NONBLOCK) ...

  9. ipc原理linux,传统的Linux中IPC通信原理

    在了解 Binder 跨进程通信原理之前, 我们先了解一下 Linux 传统的进程间通信的概念和基本原理, 这样有助于我们更好的理解 Binder 的通信原理. 这个部分基本都是理论, 基础不是很好的 ...

最新文章

  1. 【PAT (Basic Level) 】1015 德才论 (25 分)
  2. Dockerfile基本语法
  3. CentOS 7 VNC 配置
  4. boost::math模块实现将三次 b 样条插值器用于规则间隔的数据的测试程序
  5. java笔记javaweb部分
  6. 使用分发列表过滤BGP路由
  7. CVPR 2021 Oral | Transformer!UP-DETR:无监督预训练检测器
  8. 其中一个页签慢_房建工程全套技术交底,720页Word版表格,各分部分项全覆盖...
  9. 云计算学习笔记002---云计算的理解及介绍,google云计算平台实现原理
  10. 批处理脚本手动双击可以执行,但计划任务中执行失败
  11. Java Vistor 设计模式
  12. Docker教程小白实操入门(7)--基于Commit定制镜像
  13. C#中ManualResetEvent用法总结
  14. 手机ppi排行测试软件,依然是目前屏幕色准表现最好的智能手机:iPhone XS 屏幕测试...
  15. android 触摸接口,Android 多点触摸接口
  16. 条形码生成软件如何制作A级条码
  17. UGUI文本颜色渐变
  18. 网易云动态小视频下载方法
  19. ROS系统中编写多个C++文件时,主文件调用其它文件函数或类时出现:对“xxxxxx“未定义的引用问题记录
  20. 惠州学院计算机基础课程配套练习系统

热门文章

  1. 拼多多稳了,字节跳动开发新APP,是谁杀死了淘宝?
  2. 数字新消费重塑新中部,岳麓峰会再汇“长沙内能”
  3. linux中jpg文件,Linux下压缩和优化jpg与png图片的方法
  4. 汉仪尚巍手书_官宣,汉仪字库入选“十大著作权合作伙伴”啦!
  5. 调整分区个数_在重装系统的过程中,硬盘如何分区呢?
  6. html 右下角弹窗,javascript实现的右下角弹窗实例
  7. python求函数曲率_【Python】车道线拟合曲线的曲率半径计算公式及代码
  8. python爬虫学习(一) requests模块
  9. java ssm常用注解_SSM框架中常用的注解
  10. 域socket(domain socket)和ipsocket(TCP/IP socket)区别