在内部链接中关闭 EventSource 时如何避免使用全局变量?

How to avoid using a global variable, when closing an EventSource in internal links?

我有一个 Web 应用程序,其中一些内部页面使用 EventSource 从服务器接收实时更新。

客户端代码如下所示:

var LiveClient = (function() {
    return {
        live: function(i) {
            var source = new EventSource("/stream/tick");
            source.addEventListener('messages.keepalive', function(e) {
                console.log("Client "+ i + ' received a message.');
            });
        }
    };
})();

您可以在 heroku 上看到现场演示:http://eventsourcetest.herokuapp.com/test/test/1。如果您打开开发人员控制台,您将看到每次收到事件时都会打印一条消息。

问题是当访问内部链接时,EventSource 保持打开状态,导致即使在访问者从一个页面移动到另一个页面后仍会打印消息 - 因此如果您访问顶部的三个链接,您将收到消息来自三个来源。

如何在用户从一个内部页面移动到另一个内部页面后关闭之前的连接?

我尝试过的一个变通方法是为 EventSource 对象使用全局变量,如下所示:

var LiveClient = (function() {
    return {
        live_global: function(i) {
            // We set source as global, otherwise we were left
            // with sources remaining open after visiting internal
            // pages
            if (typeof source != "undefined" && source != null) {
                if (source.OPEN) {
                    source.close();
                    console.log("Closed source");
                }
            }
            source = new EventSource("/stream/tick");
            source.addEventListener('messages.keepalive', function(e) {
                console.log("Client "+ i + ' received a message.');
            });
        }
    };
})();

此处演示:http://eventsourcetest.herokuapp.com/test/test_global/1,但我正在寻找一种尽可能避免使用全局变量的解决方案。

生成的HTML代码为:

  <a href="/test/test_global/1">Page 1</a> |
  <a href="/test/test_global/2">Page 2</a> |
  <a href="/test/test_global/3">Page 3</a> |

<p>This is page 3</p>
<script>
  $(function() {
    LiveClient.live_global(3);
  });
</script>

LiveClient.live_global(1); 用于全局变量的情况。

试试这个。我还没有测试过。如果可行,您可以将 LiveClient.source 替换为 this.source,我觉得这样更干净。

  var LiveClient = (function() {
    return {
        source: null,
        live_global: function(i) {
            // We set source as global, otherwise we were left
            // with sources remaining open after visiting internal
            // pages
            if (typeof LiveClient.source != "undefined" && LiveClient.source != null) {
                if (source.OPEN) {
                    source.close();
                    console.log("Closed source");
                }
            }
            LiveClient.source = new EventSource("/stream/tick");
            LiveClient.source.addEventListener('messages.keepalive', function(e) {
                console.log("Client "+ i + ' received a message.');
            });
        }
    };
})();