Electron 在鸿蒙 PC 上跑 webview,我是怎么把首屏从 4.2s 干到 1.1s 的

Electron 在鸿蒙 PC 上跑 webview,我是怎么把首屏从 4.2s 干到 1.1s 的


一、事情是这样的

我手头在做一个 App,叫雷达鸭,鸿蒙 PC 版是直接用 Electron 套壳跑的。同一份代码,我同事在 Windows 上点开是 800ms 出首页,我在他那台鸿蒙 PC 伴侣上点开是......你看:

复制代码
[Windows 11]   首屏渲染:812ms
[鸿蒙 PC]      首屏渲染:4237ms

差了 5 倍。我当时第一反应是鸿蒙的 Chromium 内核版本老,于是查了一遍:

  • Electron 28.0 内置 Chromium 120
  • 鸿蒙 PC 的 WebView 内核(ArkWeb)版本号 120+ ✓

内核是新的。那为啥慢?

我用 app.getAppMetrics() 把进程指标全打出来,又用 Chrome DevTools 远程调试挂上去看 Network 面板,发现一个反常的现象:

所有静态资源(JS/CSS/图片)在鸿蒙 PC 上的 Waiting (TTFB) 时间几乎是 Windows 的 3 倍。

但这些资源都是 file:// 协议从本地读的,根本不应该有 TTFB。我盯着 DevTools 看了十分钟,差点把屏幕戳穿。

二、被我忽略的"假后台"机制

直到我翻到 Electron 官方一份边角文档------就是 Electron 性能优化建议 里第四小节,提到一个东西:

When a window is in the background, Electron will throttle timers and animations to reduce CPU usage. This can be useful for power consumption, but it can also cause performance issues if your app does heavy work in the background.

说白了,Electron 默认开启了一个后台节流机制。如果你的窗口在用户视角里是"非激活状态",它会自动降频渲染、节流 JS 定时器。

我一看,鸿蒙 PC 上我的应用窗口启动时的 z-order 是低于系统桌面图标的。我点开应用的瞬间,窗口从"后台"切到"前台",但 Electron 内部的状态机有约 200ms 的延迟才反应过来。

这 200ms 里,首屏的 HTML 已经加载完毕,但 JS 执行被节流,渲染管线被卡住。等到节流解除,开始绘制,4 秒就这么过去了。

三、那个被雪藏的参数

解决方案出乎意料地简单------关掉这个节流:

javascript 复制代码
// main.js
const { app, BrowserWindow } = require('electron')

app.commandLine.appendSwitch(
  'disable-renderer-backgrounding',
  '--disable-renderer-backgrounding'
)
app.commandLine.appendSwitch(
  'disable-background-timer-throttling',
  '--disable-background-timer-throttling'
)
app.commandLine.appendSwitch(
  'disable-backgrounding-occluded-windows',
  '--disable-backgrounding-occluded-windows'
)

app.whenReady().then(() => {
  const win = new BrowserWindow({
    width: 1280,
    height: 800,
    webPreferences: {
      backgroundThrottling: false,  // 这一行才是关键
      preload: path.join(__dirname, 'preload.js'),
      contextIsolation: true,
      nodeIntegration: false,
    },
  })
  win.loadFile('index.html')
})

webPreferences.backgroundThrottling: false 是显式关闭窗口级节流,前面三个 appendSwitch 是从 Chromium 命令行层兜底。两个都得加,只加一个实测会漏掉一部分场景。

我改完打包,跑了一轮:

优化项 首屏
原始版本 4237ms
+ backgroundThrottling:false 2180ms
+ 三个 appendSwitch 1143ms
+ preload 拆分(见下) 1080ms

backgroundThrottling 这一项就吃掉了 50% 的优化空间。文档里就一句话带过,鬼知道踩坑的人有多少。

四、preload 拆分的隐藏收益

顺手再提一个相关技巧。Electron 的 preload 脚本默认是同步加载的,会阻塞首屏渲染。如果你的 preload 里有 require 了一堆 npm 包(特别是带 native binding 的),首屏会更慢。

我当时的 preload 里有个 require('sqlite3'),光初始化就 600ms。拆成异步加载:

javascript 复制代码
// preload.js
const { contextBridge } = require('electron')

// 同步的、必须阻塞的(少量)
contextBridge.exposeInMainWorld('appReady', true)

// 异步加载的(用 ipc 走)
contextBridge.exposeInMainWorld('db', {
  query: (sql) => window.electronAPI.query(sql),
})
javascript 复制代码
// main.js
ipcMain.handle('db:query', async (event, sql) => {
  const sqlite3 = require('sqlite3')  // 懒加载
  // ...
})

这样 sqlite3 不会在首屏阶段同步阻塞 window.appReady 的暴露。优化后能再砍 60-80ms,蚊子腿也是肉。

五、我的反思

官方文档不一定写得对 ------"backgroundThrottling 默认开启"这个行为,在桌面端是合理的(你切走窗口时省电),但在鸿蒙 PC 这种窗口 z-order 行为跟 Windows 不一样的环境里,就变成了性能陷阱。

我后来还发现另一个类似的情况:鸿蒙 PC 的 Electron 窗口在用户最小化后 会自动进入类后台状态,但恢复时不会主动触发 visibilitychange 事件 。这导致我代码里的 document.addEventListener('visibilitychange', ...) 在鸿蒙 PC 上根本没反应。Windows 上没问题,鸿蒙上死活不触发。

最后没办法,我自己加了个轮询:

javascript 复制代码
let lastHidden = document.hidden
setInterval(() => {
  if (lastHidden !== document.hidden) {
    document.dispatchEvent(new Event('visibilitychange'))
    lastHidden = document.hidden
  }
}, 500)

丑是丑了点,但管用。

六、一个我最近开始犹豫的方案

最后说点掏心窝的:如果你正在考虑要不要上 Electron 跑鸿蒙 PC,我个人更建议你直接用鸿蒙原生 ArkWeb(WebView)

原因有三条:

  1. 性能差距抹不平。即使我优化到 1.1s,鸿蒙原生 WebView 同样页面是 400ms 出头。这是底层 IPC 的差距,不是代码能解决的。
  2. 安装包体积。Electron 打出来 180MB,ArkWeb 套壳的元服务只有 30MB。用户在华为应用市场看到 180MB 的安装包,下载意愿会打折扣。
  3. 审核麻烦。雷达鸭上架时,审核员问了一句"为什么需要 Electron",我解释了半天跨端代码复用,最后被打回要求补充说明。

我现在新做的页面已经默认 ArkTS + ArkWeb 写原生了,Electron 只用来跑老的历史包袱。除非你有强需求(比如必须用某个 Electron 专属的 Node 模块),否则真的别硬上 Electron。


写到这里有点累了。文章里 1.1s 那个数字是我在 5 次跑分中取的中位数,最快一次 980ms,最慢 1280ms。如果你想自己复现我的测试环境,可以装个 electron-to-chromium 工具看版本对齐情况。

你最近在鸿蒙 PC 上跑 Electron 踩过什么坑?留言聊聊。


关于作者:十年以上软件开发老兵,软件设计师 + 注册人工智能工程师 + agent 工程师,平时主要写鸿蒙 ArkTS 北向开发和 Web 前端,最近在折腾 AI 自动化提效。不定期在 CSDN 分享一些鸿蒙 / AI 方向的实战笔记。

本文遵循 MIT 协议,转载请注明出处。

相关推荐
YM52e5 小时前
鸿蒙ArkTS实战项目 - 门店陈列巡检台:巡检卡片与多列切换实现
学习·华为·harmonyos
lilian2336 小时前
Harmony os 技术实战|拼豆制图27:用单字符编码承载 50 张 70×70 图纸
前端·数据库·华为·harmonyos
NeilCarmack9 小时前
Deepseek-harness增加桌面版端序列:第 2 讲 · spawn Electron:当前进程如何“交棒“
前端·javascript·electron
HwJack2012 小时前
UIAbility 生命周期全链路:从冷启动到热启动的实战笔记
笔记·华为·harmonyos
梦想不只是梦与想12 小时前
鸿蒙 AppGallery Connect:应用创建(二)
harmonyos·appgallery·创建应用
●VON14 小时前
芯笺 Markdown:面向 HarmonyOS PC 的本地优先 Markdown 编辑器
华为·编辑器·harmonyos·鸿蒙
世人万千丶14 小时前
鸿蒙项目实战 - 社区活动编排板:标签云布局算法与自动换行
学习·算法·华为·harmonyos·鸿蒙
YM52e16 小时前
鸿蒙ArkTS项目实战 - 门店陈列巡检台:完整代码与运行效果
学习·华为·harmonyos
贾伟康16 小时前
【中国方言题库|06】HarmonyOS ArkTS 闽南语与客家话实战:统一分库页面导航与空状态
harmonyos·arkts·arkui·router·空状态
贾伟康17 小时前
【中国方言题库|07】HarmonyOS ArkTS 方言练习实战:推进题目、提交答案并同步统计
harmonyos·arkts·数据持久化·状态管理·arkui