在应用软件开发过程中,获取设备信息是一项重要的基础性功能,在适配不同规格设备,优化用户使用体验、进行软件运行数据分析等方面起着至关重要的作用。npm社区中大名鼎鼎的 systeminformation 便是非常优秀的提供此项功能的库。然而在我从事Electron工作的使用过程中,也发现了其一些小小的问题,以下是我发现的问题以及给出的解决办法。

背景

工作过程中发现在部分设备上命令行提示符(cmd)使用权限的禁用会导致 APP 无法正常启动。对此我进行了问题排查,最终锁定在 systeminformation 库获取设备信息的 shell 调用上。针对此问题我调研并最终决定采用封装C++调用系统API的Node Native Modules,绕开命令行调用。

研究环境

Electron Windows运行环境下(耗时研究中,在macOS环境下也做了对比,但性能提升不明显)

研究过程

调用过程

从上图我们可以看到,C++封装可以跳过node、shell、wmic的层层调用,直抵WMI,获取设备信息需要命令行提示符(cmd)使用权限的问题迎刃而解。此时我们不禁发问,既然跳过了如此多层调用,那在调用耗时上是不是有性能提升呢?

耗时研究

首先公布结论,毫无疑问的,使用C++调用Native API确实可以节省耗时。

在深入对比研究C++模块与通过node的child_process.exec命令调用的时长影响以及编写 node-systeminformation 模块的过程中,也先后经历C++封装wmic和C++封装wmi两版底层实现。wmic实现调用耗时在1000ms左右,耗时已降低了一倍左右,但经测试发现wmic调用会导致闪烁出现cmd窗口,严重影响用户体验。进而改用WMI调用,WMI调用耗时在40ms左右,并没有额外的副作用。而wmic会导致闪烁出现cmd窗口也正是因为wmic是对WMI的一层命令封装锁导致的。

性能瓶颈

研究中发现WMI的性能取决于WQL(类SQL)语法的查询性能,所以进一步优化我们获取设备信息的查询语句,可以得到更大的性能提升。

实际应用

实际应用过程中发现使用 node-addon-api 开发的Native Modules 在打包同时输出mac和mas环境的产物时rebuild环节会报错,经查为electron-builder工具中app-builder-lib模块问题,目前我已对此问题进行了先行补丁修复(PR-7744),已可正常使用。

现在electron-builder 24.6.5 版本已合并此修复。🥳

结果

耗时对比

方式 三方库(node exec封装) C++ wmic封装 C++ wmi封装
耗时 ~2000ms ~1000ms ~40ms

其他优势

  • C++封装全部为同步API ,逻辑简单,代码清晰;
  • 自研封装可做到颗粒度更细;
  • 获取信息更准确(三方库的封装方式对于较新的系统版本常有获取不到的问题);
  • 无须等待 Electron ready(设备分辨率由 Electron API 提供);
  • 可以绕开命令行提示符(cmd)的使用,降低APP对于系统权限的要求,增强稳定性;
  • 绕开命令行提示符(cmd)的使用,还可以避免命令行提示符输出结果的乱码问题。