Electron启动出现白屏问题的解决方案

 更新时间:2024年05月23日 11:44:08   作者:前端周公子  
对于 Web 开发者使用 Electron 构建桌面应用程序时,经常会遇到如上图所示的一个问题,在应用窗口创建完成到页面加载出来的这段时间里,出现了长时间的白屏,本文就来探索基于 Electron 场景下启动白屏的解决方案,需要的朋友可以参考下

对于 Web 开发者使用 Electron 构建桌面应用程序时,经常会遇到如上图所示的一个问题 —— 窗口加载过程中长时间白屏。在应用窗口创建完成到页面加载出来的这段时间里,出现了长时间的白屏,这个问题对于前端开发来说是一个老生常谈的问题,纯 Web 端可能就是异步加载、静态资源压缩、CDN 以及骨架屏等等优化方案,但是如果是开发 Electron 应用,场景又有些许不同,因此我们也不能完全按照通用的前端解决白屏的方案进行处理,本文就来探索基于 Electron 场景下启动白屏的解决方案。

问题原因分析

1. Electron 主进程加载时间过长

Electron 应用在启动时,需要先加载主进程,然后由主进程去创建浏览器窗口和加载页面。如果主进程加载时间过长,就会导致应用一直停留在空白窗口,出现白屏。

主进程加载时间长的原因可以有:

  • 初始化逻辑复杂,比如加载大量数据、执行计算任务等
  • 主进程依赖的模块加载时间长,例如 Native 模块编译耗时
  • 主进程代码进行了大量同步 I/O 操作,阻塞了事件循环

2. Web 部分性能优化不足

浏览器窗口加载 HTML、JavaScript、CSS 等静态资源是一个渐进的过程,如果资源体积过大,加载时间过长,在加载过程中就会短暂出现白屏,这一点其实就是我们常说的前端首屏加载时间过长的问题。导致 Web 加载时间过长的原因可以是:

  • 页面体积大,如加载过多图片、视频等大资源
  • 没有代码拆分,一次加载全部 Bundles
  • 缺乏缓存机制,资源无法命中缓存
  • 主线程运算量大,频繁阻塞渲染

解决方案

1. 常规 Web 端性能优化

Web 端加载渲染过程中的白屏,可以采用常规前端的性能优化手段:

  • 代码拆分,异步加载,避免大包导致的加载时间过长
  • 静态资源压缩合并、CDN 加速,减少资源加载时间
  • 使用骨架屏技术,先提供页面骨架,优化用户体验
  • 减少主线程工作量,比如使用 Web Worker 进行复杂计算
  • 避免频繁布局重排,优化 DOM 操作

以上优化可以明显减少 HTML 和资源加载渲染的时,缩短白屏现象。还是那句话,纯 Web 端的性能优化对于前端开发来说老生常谈,我这边不做详细的赘述,不提供实际代码,开发者可以参考其他大佬写的性能优化文章,本文主要针对的是 Electron 启动白屏过长的问题,因为体验下来 Electron 白屏的本质问题还是要通过 Electron 自身来解决~

2. 控制 Electron 主进程加载时机

Electron 启动长时间白屏的本质原因,前面特意强调了,解决方案还是得看 Electron 自身的加载时机,因为我这边将 Web 部分的代码打包启动,白屏时间是非常短的,与上面动图里肉眼可见的白屏时间形成了鲜明的对比。所以为了解决这个问题,我们还是要探寻 Electron 的加载时机,通过对 Electron 的启动流程分析,我们发现:

  • 如果在主进程准备就绪之前就创建并显示浏览器窗口,由于此时渲染进程和页面还未开始加载,窗口内自然就是空白,因此需要确保在合适的时机创建窗口。
  • 反之如果创建窗口后,又长时间不调用 window.show() 显示窗口,那么窗口会一直在后台加载页面,用户也会看不到,从而出现白屏的效果。

因此我们可以通过控制主进程的 Ready 事件时机以及 Window 窗口的加载时机来对这个问题进行优化,同样的关于加载时机我们也可以有两种方案进行优化:

  • 通过监听 BrowserWindow 上面的 ready-to-show 事件控制窗口显示
// 解决白屏问题
app.whenReady().then(() => {
  // 将创建窗口的代码放在 `app.whenReady` 事件回调中,确保主进程启动完成后再创建窗口
  const mainWindow = new BrowserWindow({ show:false });
  // 加载页面
  mainWindow.loadURL('index.html');
  // 在 ready-to-show 事件中显示窗口
  mainWindow..once("ready-to-show", () => {
     mainWindow.show();
  });
});

上述代码通过操作 app.whenReady()BrowserWindowmainWindow.once('ready-to-show') 这几个 Electron 核心启动 API,优雅地处理了窗口隐藏 + 页面加载 + 窗口显示等问题,详细流程如下:

  • 将创建窗口的代码放在 app.whenReady 事件回调中,确保主进程启动完成后再创建窗口

  • 创建窗口的时候让窗口隐藏不显示{ show: false },避免页面没加载完成导致的白屏

  • 窗口加载页面 win.loadURL,也就是说窗口虽然隐藏了,但是不耽误加载页面

  • 通过 ready-to-show 事件来判断窗口是否已经准备好,这个事件其实就代表页面已经加载完成了,因此此时调用 mainWidnow.show() 让窗口显示就解决了白屏的问题

  • 通过监听 BrowserWindow.webContents 上面的 did-finish-load 或者 dom-ready 事件来控制窗口显示
app.whenReady().then(() => {
  // 将创建窗口的代码放在 `app.whenReady` 事件回调中,确保主进程启动完成后再创建窗口
  const mainWindow = new BrowserWindow({ show:false });
  // 加载页面
  mainWindow.loadURL(indexPage);
  // 通过 webContents 对应事件来处理窗口显示
  mainWindow.webContents.on("did-finish-load", () => {
     mainWindow.show();
  });
});

此方案与上述方案的唯一区别就是,第一个使用的是 BrowserWindow 的事件来处理,而此方案通过判断 BrowserWindow.webContents 这个对象,这个对象是 Electron 中用来渲染以及控制 Web 页面的,因此我们可以更直接的使用 did-finish-load 或者直接 dom-ready 这两个事件来判断页面是否加载完成,这两个 API 的含义相信前端开发者都不陌生,页面加载完成以及 DOM Ready 都是前端的概念,通过这种方式也是可以解决启动白屏的。

最后解决完成的效果如下:

总结

从上图来看最终的效果还是不错的,当窗口出现的一瞬间页面就直接加载完成了,不过细心的小伙伴应该会发现,这个方案属于偷梁换柱,给用户的感觉是窗口出现的时候页面就有内容了,但是其实窗口没出现的时间是有空档期的,大概就是下面这个意思:

从上图以及实际效果来看,其实我们的启动时间是没有发生改变的,但是因为端上应用和我们纯 Web 应用的使用场景不同,它自身就是有应用的启动时间,所以空档期如果不长,这个方案的体验还是可以的。但是如果前面的空档期过长,那么可能就是 Electron 启动的时候加载资源过多造成的了,就需要其他优化方案了。由此也可以见得其实对于用户体验来说,可能我们的产品性能并不一定有提升,只要从场景出发从用户角度去考虑问题,其实就能提升整个应用的体验。

以上就是Electron启动出现白屏问题的解决方案的详细内容,更多关于Electron启动白屏的资料请关注脚本之家其它相关文章!

相关文章

  • 主页面中的两个iframe实现鼠标拖动改变其大小

    主页面中的两个iframe实现鼠标拖动改变其大小

    iframe实现鼠标拖动改变其大小在一个页面中的两个iframe的情况下,此方法相当实用,感兴趣的各位不妨参考下,或许对你有所帮助
    2013-04-04
  • BootStrap点击保存后实现模态框自动关闭的思路(模态框)

    BootStrap点击保存后实现模态框自动关闭的思路(模态框)

    这篇文章主要介绍了BootStrap点击保存后实现模态框自动关闭的思路(模态框),需要的朋友可以参考下
    2017-09-09
  • TypeScript泛型约束条件示例详解

    TypeScript泛型约束条件示例详解

    有了泛型之后一个函数或容器类能处理的类型一下子扩到了无限大,似乎有点失控的感觉,所以这里又产生了一个约束的概念,下面这篇文章主要给大家介绍了关于TypeScript泛型约束条件的相关资料,需要的朋友可以参考下
    2022-04-04
  • Js和VUE实现跑马灯效果

    Js和VUE实现跑马灯效果

    这篇文章主要为大家详细介绍了Js和VUE实现跑马灯效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-05-05
  • js遍历json的key和value的实例

    js遍历json的key和value的实例

    下面小编就为大家带来一篇js遍历json的key和value的实例。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-01-01
  • javascript异步编程

    javascript异步编程

    如果编程加入了时间的概念就一切变得非常复杂。通常我们的程序是飞快地解析执行,一毫秒紧接着一毫秒,从上至下地执行,这称之为同步。但如果我们想让后台的程序不等前面的程序执行,就执行呢,于是就有了异步的概念。
    2010-06-06
  • JS跳转手机站url的若干注意事项

    JS跳转手机站url的若干注意事项

    去年年底开发了一个手机站平台,遇到了很多坎,今天小编给大家分享下使用JS跳转手机站url的若干注意事项,需要的朋友参考下吧
    2017-10-10
  • javascript闭包的使用之按钮切换功能

    javascript闭包的使用之按钮切换功能

    闭包就是能够读取其他函数内部变量的函数.这篇文章通过实例代码给大家介绍了javascript闭包的使用之按钮切换功能,感兴趣的朋友一起看看吧
    2018-08-08
  • JS+DIV实现拖动效果

    JS+DIV实现拖动效果

    这篇文章主要为大家详细介绍了JS+DIV实现拖动效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-02-02
  • JS开发中基本数据类型具体有哪几种

    JS开发中基本数据类型具体有哪几种

    JS的数据类型包括基本数据类型、复杂数据类型和特殊数据类型,今天我们主要先讲解一下基本数据类型。感兴趣的朋友一起看看吧
    2017-10-10

最新评论