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. 进程间通信方法

主进程和渲染进程通过 ipcMainipcRenderer 进行通信。

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_threadsSharedArrayBuffer

    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 是基于消息传递的机制。它不是内存共享或内存映射文件。

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

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

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

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

9. WebAssembly