Electron BrowserView层级管理优化:基于位移的创新方案
背景
为了提高直播间的稳定性和用户体验,我们在 Electron 客户端采用了多容器(多 BV,Browser View)底层架构。这些容器分别用于不同的功能模块,如直播间、互动题、通用互动、系统 UI 等等,每个模块都有独立的容器。这种多容器架构能更好地分离关注点,提高系统的可维护性和扩展性。然而,这种架构也带来了一些新的挑战,尤其是在容器层级管理方面。
在传统的布局设计中,CSS 可以通过 z-index
来轻量地调整 DOM 元素的层级,但在多容器架构中,由于每个容器在 Electron 中都有独立的渲染进程和视图,它们无法通过简单的 z-index
机制来控制层级。此时,Electron 提供的 setTopBrowserView
方法成为了调整容器层级的主要手段。然而,频繁调用 setTopBrowserView
来调整容器的层级会带来显著的性能损耗,尤其是在一些需要频繁调整层级的场景中。
Electron 中 setTopBrowserView 成本消耗
setTopBrowserView
是 Electron 提供的用于调整浏览器视图层级的方法。通过调用该方法,可以将指定的容器设置为最上层,确保其能够显示在其他容器之上。然而,这种方法存在显著的缺点:
- 性能损耗:
BrowserView
的层级调整可能涉及底层 GPU 渲染的重新排序,尤其是在多容器架构中,当多个视图的层级频繁变动时,GPU 的渲染操作可能会变得更为繁重,导致渲染延迟和性能下降。 - 事件延迟:由于
setTopBrowserView
调用是基于事件驱动的,且涉及到底层的渲染进程,频繁的调用可能会引入操作延迟,尤其在容器数量较多或者交互场景较复杂时,延迟表现尤为明显。 - 层级调整的复杂性:在多容器架构下,管理层级的操作变得尤为复杂。例如,如果我们需要将容器
d
调整到底部并保持容器a
、b
、c
的顺序不变,必须依次调用setTop
将a
、b
、c
的层级调整为顶部,然后再调整d
。这种操作不仅繁琐,而且容易出现错误,导致层级顺序的混乱和视图的不稳定。
层级管理仅依赖 setTopBrowserView
的弊端
在传统的基于 setTopBrowserView
的层级调整方案中,每次调整都需要重复执行一系列的 setTop
操作,这样会导致以下问题:
- 不便于管理:每次层级调整都涉及到多个容器的逐一操作,这使得管理变得非常困难。特别是在容器数量较多时,频繁的层级调整可能导致操作失误或遗漏,最终影响系统的稳定性。
- 重复操作的延迟:在直播间的实时场景中,信令时机的把握至关重要。频繁的层级调整会导致多个容器的状态和层级出现不同步的情况,增加了事件的延迟,影响了用户体验。
- 容器切换错乱:多次重复的层级调整可能导致容器顺序错乱,无法保证容器的展示顺序与预期一致,尤其是在复杂的交互场景下,可能会发生不可预料的 UI 错乱。
创新思维 - 层级调整为位移
为了解决上述问题,我们提出了将层级调整从传统的 setTopBrowserView
调整方式,转变为基于位移(Bounding Box 更新)的方式。这种思路的核心在于,将容器的层级结构固定不变,仅通过更新容器的可视区域来控制其显示顺序,从而避免了频繁的 setTop
操作。
具体实现
- 固定层级结构:我们不再依赖于
setTopBrowserView
进行频繁的层级调整,而是将容器的显示顺序通过位移的方式进行管理。每个容器在初始化时,都会根据其功能和显示顺序被固定在一定的层级位置。 - 通过 Bounding Box 更新位置:当需要展示某个容器时,只需通过
updateBvBounding
方法更新容器的显示区域(Bounding Box)。这一操作仅仅是更新容器的位置和可视区域,无需修改容器的层级,从而减少了性能损耗。 - 无需频繁调整层级:由于容器的层级关系已经固定,当容器需要显示时,只需将其位移到可视区域内即可。这种方式比传统的
setTop
调整要高效得多,且避免了容器层级混乱的风险。
优势
- 提升性能:通过减少
setTopBrowserView
的调用,避免了频繁的渲染更新,显著提高了性能。特别是在直播过程中频繁的容器切换中,新的方案能够保证更平滑的用户体验。 - 简化管理:由于层级结构是固定的,我们只需要关注容器的位置和可视区域,而不再需要频繁调整容器的层级顺序。这使得容器的管理变得更加简洁高效,减少了出错的机会。
- 减少延迟:通过位移方式来管理容器的显示顺序,减少了由于事件驱动的层级调整带来的延迟,从而提高了实时互动场景中的响应速度。
- 增强稳定性:固定层级结构和位置更新的方案,避免了频繁的层级切换和容器状态不一致的问题,使得整个直播系统在高负载和复杂场景下表现更加稳定。
问题
通过测试发现,如果直接将容器完全移出可视区域(即将容器的位置调整到完全不可见的区域),某些容器的事件响应会受到影响,导致无法正常执行。这是因为 Electron 或 Web 环境下,某些事件(如点击、焦点等)会受到视图的可见性和位置的影响。因此,单纯地将容器完全移出视图并不完全符合我们的需求。
解决方案 - 位移至用户看不到的区域
基于上述问题,我们提出了将容器移到可视区外,但保持容器的可见区域部分在可视范围内(例如只暴露 1px 的区域)。这样做的目的是:
- 保持事件可执行性:通过将容器的 1px 露出在屏幕的左、右或下角,即使容器几乎不可见,它仍然能够接收事件。这确保了容器在被移出主视图区域时,其内部的事件(如点击、交互等)能够继续触发,从而避免因容器完全不可见而导致的事件丢失问题。
- 避免视觉干扰:容器只有 1px 的可见区域,用户几乎无法感知容器的存在。这保证了 UI 的清爽和无干扰,同时能够确保容器的事件和行为仍然有效。
- 简化可视区管理:将容器移动到用户看不见的位置(如左、右或下角)而不是完全移出可视区域,避免了因容器完全消失而导致的状态更新或渲染问题,进一步简化了多容器架构的管理和调度。
总结
通过创新性地将传统的层级管理方式转变为基于位移的方式,我们能够有效地提高多容器架构下的性能、简化容器的管理,并降低因频繁层级调整带来的延迟和错乱问题。相比于传统的 setTopBrowserView
方法,位移方案在当前场景下无疑是更加高效且可控的解决方案,为直播间的稳定性和用户体验提供了坚实的保障