Skip to content

精通 Electron 关键技术点 ​

构建 Electron 应用需要对其核心技术和常见问题有深入的了解。以下是 Electron 的一些关键技术点,为开发者提供全面的参考:

一、基础篇 ​

1. Node.js 模块 ​

1.1. fs 模块 ​

  • 简介:fs 模块为我们提供了操作文件系统的功能。
  • 主要功能:读写文件、遍历目录、创建/删除目录、查看文件状态等。

1.2. path 模块 ​

  • 简介:path 模块用于处理文件和目录的路径。
  • 主要功能:拼接路径、获取文件扩展名、解析路径、规范化路径等。

1.3. os 模块 ​

  • 简介:os 模块用于获取关于操作系统的信息。
  • 主要功能:获取系统平台、系统内存信息、CPU 信息、主机名、网络接口等。

1.4. events 模块 ​

  • 简介:events 模块用于处理事件。
  • 主要功能:创建和管理自定义事件、触发事件、监听事件等。

1.5. buffer 模块 ​

  • 简介:buffer 模块用于处理二进制数据。
  • 主要功能:创建缓冲区、读写数据、转换为其他格式如 Base64、切片、复制等。

2. app 模块 ​

2.1. 获取用户安装目录 ​

  • 方法:使用 app 模块的 getPath 方法。

2.2. 设置应用自启动 ​

  • 方法:使用 app 模块的 setLoginItemSettings 方法。

3. 进程间通信 ​

3.1. 进程间通信方法 ​

主进程和渲染进程通过 ipcMain 和 ipcRenderer 进行通信。

3.2. 消息传递 ​

主进程与渲染进程间可以发送和接收消息。

4. BrowserWindow 模块 ​

4.1. 创建自定义窗口 ​

使用 BrowserWindow 创建自定义窗口,支持多种窗口属性和方法。

5. 系统托盘菜单 ​

5.1. 托盘菜单操作 ​

从创建托盘图标到定义托盘菜单项,系统托盘为应用提供了更多的交互可能。

二、进阶篇 ​

1. 自动更新 ​

了解 Electron 的自动更新机制,如何配置、发布和应用更新。

2. 代码签名 ​

为 Electron 应用进行代码签名,确保应用的完整性和来源。

3. 调用 dll 动态库 ​

如何在 Electron 中调用外部 DLL 动态库,实现更复杂的功能。

4. Electron Builder 打包配置 ​

详解 Electron Builder 的配置项,实现应用的定制化打包。

5. 调用系统级别的 API ​

利用 Node.js 的 ffi 模块或 Electron 提供的 API,调用系统级别的 API。

6. 使用 node c++ 插件 ​

了解如何使用 node-gyp 编译和加载 C++ 插件,为 Electron 应用增加性能和功能。

7. 进程间通信(消息传递、内存共享等) ​

内存共享 ​

在 Node.js 中,你可以通过以下方式实现内存共享:

  1. 使用 Worker Threads:

    自 Node.js 10.5.0 开始,一个叫做 worker_threads 的模块被引入了。这个模块提供了一种在 Node.js 中创建多线程的能力,并且支持使用 SharedArrayBuffer 来进行线程间的内存共享。

    这里有一个简单的例子来展示如何使用 worker_threads 和 SharedArrayBuffer:

    javascript
    const {
      Worker,
      isMainThread,
      parentPort,
      workerData,
    } = require("worker_threads");
    
    if (isMainThread) {
      // 主线程
      const sharedBuffer = new SharedArrayBuffer(
        10 * Int32Array.BYTES_PER_ELEMENT
      );
      const sharedArray = new Int32Array(sharedBuffer);
      sharedArray[0] = 42;
    
      const worker = new Worker(__filename, { workerData: sharedBuffer });
    
      worker.on("message", (msg) => {
        console.log(msg); // Logs "Worker sees: 42"
      });
    } else {
      // 工作线程
      const sharedArray = new Int32Array(workerData);
      parentPort.postMessage(`Worker sees: ${sharedArray[0]}`);
    }
  2. 使用 Child Processes 和 Memory-mapped Files:

    跨进程的内存共享在 Node.js 中较为复杂。一个通常的方法是使用内存映射文件,但这需要依赖第三方模块,例如之前提到的 mmap-io。

    这意味着你会创建一个文件,然后两个或更多的进程可以将此文件映射到其内存中,实现内存的共享。当一个进程修改该共享内存区域时,其他进程可以看到这些更改。

  3. 使用其他的 IPC 机制:

    除了内存映射文件之外,还有其他的跨进程通信 (IPC) 方法可用,但它们通常不是真正的内存共享。例如,你可以使用 UNIX 套接字、命名管道或其他通信机制,但这些都是基于消息传递,而不是真正的内存共享。

综上所述,真正的内存共享在 Node.js 中通常限于使用 worker_threads 模块和 SharedArrayBuffer(适用于线程)或使用内存映射文件(适用于跨进程)。如果选择使用这些方法,请确保了解并发和同步的问题,以确保数据的完整性和安全性。

  1. 使用 node c++ 插件的方式来实现

使用 Memory-mapped files(内存映射文件) ​

使用内存映射文件(Memory-mapped files)是一种在多个进程之间共享数据的技术。它允许您将文件的部分或全部映射到进程的地址空间,这使得文件的内容可以像常规内存块一样被访问。这种方式可以高效地在进程之间共享大块数据,因为不需要数据的复制或序列化。

在 Node.js 和 Electron 中,您可以使用原生模块或第三方库来实现内存映射文件。下面是使用内存映射文件的基本步骤:

  1. 安装必要的库

    例如,您可以使用 mmap-io 这个库来实现内存映射。首先,您需要安装它:

    bash
    npm install mmap-io
  2. 使用内存映射文件

    这是一个简单的示例,展示了如何使用 mmap-io:

    javascript
    const mmap = require("mmap-io");
    const fs = require("fs");
    
    // 打开一个文件
    const fd = fs.openSync("shared.dat", "a+");
    
    // 设定文件大小
    const FILE_SIZE = 1024 * 1024; // 1MB
    fs.ftruncateSync(fd, FILE_SIZE);
    
    // 映射文件到内存
    const buffer = mmap.map(
      FILE_SIZE, // 映射大小
      mmap.PROT_WRITE, // 可写
      mmap.MAP_SHARED, // 共享模式
      fd,
      0 // 文件的偏移
    );
    
    // 之后你可以像操作常规 Buffer 一样操作这个 buffer
    buffer.write("Hello, World!", 0);
    
    // 当你完成后,可以解除映射
    mmap.unmap(buffer);
    
    // 并关闭文件
    fs.closeSync(fd);

注意,内存映射文件涉及到操作系统级别的操作,因此在使用它们时要特别小心。确保您正确地管理文件和内存资源,以避免资源泄露或其他问题。

此外,多个进程访问同一个内存映射文件时可能会遇到并发问题。在这种情况下,您可能需要使用某种形式的进程间同步,例如信号量、互斥量或其他同步原语,以确保数据的一致性和完整性。

消息传递 ​

MessageChannel 是消息传递还是内存共享 还是内存映射文件 ?

MessageChannel 是基于消息传递的机制。它不是内存共享或内存映射文件。

当您使用 MessageChannel 的 postMessage 方法发送数据时,这些数据会通过所谓的 "structured clone algorithm" 被序列化,然后在接收端被反序列化。这意味着数据是被复制的,而不是直接共享的。

这种消息传递机制的好处是它是安全的。因为数据是复制的,所以发送和接收的两边可以独立地操作数据而不用担心对方的干扰。这与内存共享(如 SharedArrayBuffer)不同,在那种情况下,多个线程或进程可以同时访问相同的内存块,可能导致并发问题。

总之,MessageChannel 是一个基于消息传递的机制,它在发送数据时进行序列化和复制,而不是直接共享或使用内存映射文件。

8. 多进程、多线程(child process/ worker) ​

9. WebAssembly ​