浏览器跨标签通讯

即将到来的 SharedWorker API 能够在 iframe 甚至浏览器标签或窗口中传输数据。它在几年前就已在 Chrome 中得以实现,不久前也在 Firefox 上实现了,不过它在 IE 和 Safari 中仍然难觅踪影。还好,这个 API 有一种拥有广泛浏览器支持,但鲜为人知的替代方案。是时候探索它了!

现在,我需要对以下应用情景找到一个优雅的解决方案:假设有个人访问了你的网站。他依次登录,打开第二个标签页并在那个标签页里选择了注销。这时,他所打开的第一个标签页看起来仍然保留着「已登录」的状态,但这时他的所有操作要么会重定向到登录页面,要么会直接让他抓狂。更吸引人的解决方式则是判断用户是否已注销,并对页面做相应的改变。譬如可以显示一个对话框来提示用户需要重新验证,或者显示原本的登录视图。

这个功能可以通过 WebSocket API 来实现,不过这就有些小题大做了。毕竟杀鸡焉用牛刀,于是我开始寻找一些其它的跨标签页通信方式。我首先想到的就是使用 cookies 或者 localStorage ,来周期性地通过 setInterval 检查用户是否登录。对这个方案我并不满意,因为这样会把许多 CPU 周期耗费在检查一个可能自始至终都不会满足的条件上。这时候我就觉得还不如就直接用 “comet”(又名轮询)、服务器端事件或者 WebSockets 算了呢。

所以当我发现自己是在骑驴找驴的时候还是很吃惊,因为答案就是一直以来的 localStorage

你知道 localStorage 会触发一个事件吗?具体地说,不论其中的哪一项在另一个浏览上下文里被添加、修改或删除时,它都会触发一个事件。实际上,这就意味着不论在哪个浏览器的标签页里访问了 localStorage,所有其它的标签页都能通过 window 对象监听到这个事件,就像这样:

event 对象有几个相应的属性:

属性 描述
key localStroage 中被影响的键
newValue 为这个键所赋的新值
oldValue 这个键修改前的值
url 当前发生改变的页面 URL

不论某个标签页在何时修改了 localStorage,都会对其余的所有标签触发事件。这就意味着我们只要为 localStorage 赋值,就能够跨浏览器标签通信了。请看下面伪代码风格的示例:

大意就是当用户打开了两个标签页,在其中一个里执行了注销操作后返回另一个时,页面将重新载入,(如果可以的话)服务器端逻辑将把用户重定向到其它位置。这个检查只在当前标签页获得焦点时执行,这是因为用户可能在注销后立刻重新登录,这种情况下不应将其余标签页的状态全部设为已注销。

这段代码肯定还可以改进,不过它已经很好地满足了需求。更好的实现方式可能会立刻要求用户登录,但要注意它也可能以相反的方式来工作:用户登录后打开另一个已经注销的标签页时,代码会检查并重新载入页面,然后服务器(再说一遍,如果可以的话)就可以把用户重定向到登录页面的不老泉里,期盼着你能有一次打电话给这个网站的经验。

更简单的 API

localStorage API 可以说是 web 浏览器最简单的 API 之一了,并且它还享有相当不错的跨浏览器支持。不过,一些浏览器的仍然存在着 quirks,譬如无痕模式下的 Safari 在设置值时会抛出 QuotaExceededError 的异常,有某些浏览器不支持开箱即用的 JSON,还有一些旧版浏览器会让你感到沮丧。

因此,我整合了一个 local-storage 模块,为 localStorage 提供了简化的 API,从而摆脱这些 quirks,在缺少 localStorage API 时会回退到内存存储,并通过使你为特定键注册或取消注册监听器,使得对 storage 事件的使用更加容易。

截止到写这篇文章时,local-storage@1.3.1 中最新的 API 端点(译者注:2015-01-08) 如下:

  • ls(key, value?) 取得或设置键
  • ls.get(key) 取得键的值
  • ls.set(key, value) 为键指定值
  • ls.remove(key) 移除键
  • ls.on(key, fn(value, old, url)) 监听其它标签页的键值改变并触发 fn
  • ls.off(key, fn) 取消之前使用 ls.on 注册的监听器

同样值得一提的是, local-storage 注册了一个单一的 storage 对象处理器并保持你对每个键的跟踪,而不是注册多个 storage 对象。

我对学习其它跨标签页通信的底层实现方式也很有兴趣!它对离线优先的开发很有帮助,尤其是考虑到当前 SharedWorker 还需要一段时间才能迎来广泛支持,而 WebSocket 在离线使用的情境下也靠不住时,这种通信方式就更有意义了。

1 1 收藏 评论

关于作者:ewind

简介还没来得及写 :) 个人主页 · 我的文章 · 11

相关文章

可能感兴趣的话题



直接登录
跳到底部
返回顶部