如何利用 SharedWorker 优化 Vue3 项目中的数据共享

引言

大家好,我是林三心。我的座右铭是用最通俗易懂的语言讲解最难的知识点,我始终相信基础是进阶的前提。

项目背景

最近,我的一个客户提出了一个非常有趣的优化建议。

我们的项目是基于 Vue3 开发的,客户习惯通过多个浏览器标签页同时打开相同的项目,以便于快速访问多个页面。例如,客户的两个页面(尽管外观上有显著不同)在某些功能上存在相似性:

图片

这种做法可以理解,因为有些用户不喜欢在同一标签页中切换,他们觉得频繁切换很麻烦。

尽管这两个页面在外观上不同,但它们有一部分功能相似(但由于细节差异未封装成组件):

图片

这部分相似的逻辑依赖于同一接口,并采用相同的数据处理逻辑,该过程耗时较长:

  • 接口请求:3000ms,由于后端的数据获取逻辑复杂,返回的数据量庞大。
  • 数据处理:300ms,前端需要进行数据处理。

因此,客户提出了这样一个优化请求:如果逻辑是相同的,是否可以让页面一共享数据给页面二、页面三、页面四呢?

优化点分析

在考虑客户的要求之前,我们先分析一下可能的优化方案。

由于接口请求数据处理都是耗时且数据量大的操作,起初我打算将这些操作放入WebWorker中执行。

然而,在客户提出的优化需求之后,我意识到不能使用WebWorker,原因如下:

  1. 每个标签页的WebWorker都是独立的,无法共享数据。
  2. 即便使用WebWorker + IndexedDB进行数据缓存共享,依然很难共享数据状态

第一个原因比较容易理解,而第二个原因可能会让一些人困惑。为什么需要共享数据状态呢?

我们来看一下图示。数据状态的共享至关重要,因为页面二、页面三、页面四需要知道数据的状态,这有点像 Promise 的状态,可能是未缓存、缓存中、已缓存

图片

以刚才的例子为例,有两种情况:

图片

  • 情况一: 页面一打开后,点击按钮进行数据请求和缓存,随后点击页面二的按钮,此时页面二可以获取到缓存的数据,这种情况没有问题。
  • 情况二: 页面一点击按钮后 1 秒,再去点击页面二的按钮。此时页面二对页面一的数据状态一无所知,因此无法判断是发起请求,还是等待页面一的请求完成。

显然,共享数据状态是非常重要的。

采用 SharedWorker

最终,我放弃了WebWorker,转而选择了SharedWorker图片

什么是SharedWorker?可以将其理解为:SharedWorkerWebWorker类似,但它允许多个标签页共享。

当多个标签页连接同一个SharedWorker时,SharedWorker通过 port 管理每个标签页。可以说:每个标签页对应一个 port

我们通过一个简单的案例来演示SharedWorker,看看count是否能够在两个页面间共享。

图片

图片

如图所示,count成功被共享了。

图片

接下来,我们将shared-worker.js中的逻辑修改为请求数据和处理数据的代码。

图片

图片

然而,这样的写法并不能实现数据状态的共享!这实际上是进行了两次请求,优化效果并不明显。若页面一先点击再点击页面二,若实现了共享,理应同时接收到数据,但显然还没有达到最终效果。

因此,我们需要实现数据状态的共享,其实非常简单,只需利用Promise即可。

图片

最终的效果是,即使不同时点击,数据也能同时出现。

图片

结语

感谢您的阅读,我是林三心。