最近遇到一个需求场景,产品希望在打开的同一系统的多个标签之间可以同步某些信息,但又希望在所有标签关闭的情况下,下次打开就啥也没有。等于重新初始化。

 

在没有后台介入的情况下,首先想到了sessionStorage 和 localStorage。但是很遗憾,sessionStorage 不支持多个标签之间共享,即使同源也不行。localStorage 虽然可以多标签共享,但在不手动清除的情况下,信息会一直存在。都不是理想的状态。这里也不得不吐槽一下浏览器的实现,为啥不实现多一个API,综合session的实效性和local的作用范围,这样的需求场景其实是很多的。

在网上搜索了半天,尝试了一种 sessionStorage 配合 localStorage,再加上监听 storage 事件的方式。大致思路是,已打开的标签页先使用 sessionStorage 存储信息,当新打开一个标签页时,通过localStorage.setItem(‘setxxx’)触发一下 storage事件,已打开的标签就能通过 addEventerListener(‘storage’) 监听到改事件,这个时候再设置一份和sessionStorage  相同的 localStorage 数据。同样的,新打开的标签页也能监听到已打开标签页设置localStorage的事件,将数据从 localStorage 拿到,写入sessionStorage ,再清除localStorage。这样下来,想要的功能确实是能满足,但是有缺点。那就是storage事件的触发是有时间延迟的。打开新标签时,我在 new Vue实例之前触发 storage事件,当我新页面再次监听到 storage时,它的触发时间居然在 created 之后。这就很尴尬了。本来就是想在created的时候获取到同步信息的,结果你还要后来,果断不行。

 

于是,又开始了尝试 SharedWorker。直接上代码吧。

index1.html

index2.html

worker.js

要说明几点,

1、worker.js的路径问题,必须要跟页面同源,可以是绝对路径,也可以是相对路径。

2、在 worker.js里,是访问不到 window对象的,sessionStorage,localStorage等也访问不到。其他的我没尝试,估计只要是挂在window下的对象,都不能访问到。

3、我们在worker中的console.log,不能在页面的控制台查看,如果使用的是谷歌浏览器,可在地址栏输入chrome://inspect/#workers打开一个标签,如果你的worker正常加载的话,可在 Shared workers 下面看到一个列表,域名和你相同的,应该就是你的worker了,点击 inspect 可打开一个小面板,你的console 信息在那就能看到。为了方便查看,我们也可以在 new SharedWorker(path, name)的时候传入第二个参数。在Shared workers 列表里方便查看。