【问题标题】:HTML5 EventSource listener for all events?所有事件的 HTML5 EventSource 侦听器?
【发布时间】:2012-04-13 14:04:25
【问题描述】:

我在我的 JavaScript 客户端应用程序中使用 EventSource 推送通知。 我可以像这样附加事件监听器:

source.addEventListener('my_custom_event_type', function(e) {
  console.log(e.data);
}, false);

但我想监视从服务器推送的所有事件(主要用于调试),因此如果发送了某些事件但它没有事件侦听器,我可以轻松找到它。我的意思是,我不想仅仅“忽略”所有没有绑定 eventListeners 的事件。

我希望做这样的事情:

source.addEventListener('*', function(e) {
  console.debug('Event with no listener attached: ', e);
}, false);

但是像html5rocks 这样的规范和教程并没有说明这是否可能。

另一方面,它可能是一些允许监视所有服务器事件或其他东西的 firefox/chrome 扩展。这些东西对开发推送通知很有帮助。

谢谢!

【问题讨论】:

    标签: javascript html server-sent-events


    【解决方案1】:

    我自己想出了一个解决方案,它也极大地改进了 EventSource 接口。

    服务器端:不发送事件类型,只包含一个额外的数据字段(我总是使用 json)。所以不是

    event: eventName
    data: {mykey: 'myvalue'}
    

    我改为从服务器发送这个:

    data: {mykey: 'myvalue', eventName: 'eventName'}
    

    客户端:现在我可以使用 EventSource onmessage 回调,它会在每条没有事件类型的消息上触发。

    对于绑定事件侦听器,我创建了一个具有 Backbone.Event 功能的包装类。结果:

    // Server Sent Events (Event Source wrapper class)
    var MyEventSource = (function() {
    
      function MyEventSource(url) {
        var self = this;
        _.extend(this, Backbone.Events);
    
        this.source = new EventSource(url);
        this.source.onmessage = function(event) {
          var data, eventName;
          var data = JSON.parse(event.data);
          var eventName = data.eventName; delete data.eventName;
    
          // Now we can monitor all server sent events
          console.log('app.server.on ', eventName, '. Data: ', data);
    
          self.trigger(eventName, data);
        };
      }
    
      return MyEventSource;
    })();
    

    现在有了这个包装类,我可以轻松扩展功能,可以轻松监控所有服务器发送的事件,并且由于扩展 Backbone.Events,此类中的事件处理功能更加强大。

    使用示例:

    var source = new MyEventSource('url/of/source');
    
    // Add event listener
    source.on('eventName', function(data) {
      console.log(data);
    });
    
    // Fire a event (also very useful for testing and debugging!!)
    source.trigger('eventName', { mykey: 'myvalue' });
    
    // Unbind event listener (very important for complex applications)
    source.off('eventName');
    

    现在我有了一个易于处理、扩展、调试和测试的组件。

    【讨论】:

    • “Onmessage 回调在每条没有事件类型的消息上触发”。这对我来说是非常有用的信息。谢谢。
    • 仅供参考:调用onmessage = some_function; 与调用addEventListener("message", some_function); 完全相同。这很明显,没有事件类型的消息与具有“消息”事件类型的消息是相同的。
    • 你好 tothemario。出于某种原因, JSON.parse(event.data) 对我不起作用。您是否愿意提供您的服务器端方式来生成数据: {mykey: 'myvalue', eventName: 'eventName'} ?提前致谢。
    • tothemario!感谢您的回答,根据您的指导,我尝试了source.addEventListener('eventName', MyHander, false);,这在没有包装器的情况下有效。 (有关完整示例,请参见下面的答案)
    【解决方案2】:
     <script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js" type="text/javascript"></script>  
      <script>
        var content = '';
        if(typeof(EventSource)!=="undefined")
        {
          var source = new EventSource("demo_sse.php");
          source.onmessage = function(event)
          {
            content+=event.data + "<br>";
            $("#result").html(content);
          };
        }
        else
        {
          $("#result").html("Sorry, your browser does not support server-sent events...");
        }
      </script>
    

    【讨论】:

    【解决方案3】:

    我知道这不是 EventSource,但我一直在寻找相同的东西(一种在不知道其类型的情况下捕获所有传入事件的方法)。由于无法控制发送这些事件的服务器,我最终只使用 XHR 编写它,以防其他人遇到这种情况:

    function eventStream(path, callback){
        //Create XHR object
        var xhr = new XMLHttpRequest();
    
        //initialize storage for previously fetched information
        var fetched='';
    
        //Set readystatechange handler
        xhr.onreadystatechange=function(){
    
            //If the connection has been made and we have 200, process the data
            if(xhr.readyState>2 && xhr.status==200){
                //save the current response text
                var newFetched=xhr.responseText;
    
                //this is a stream, so responseText always contains everything
                //from the start of the stream, we only want the latest
                var lastFetch=xhr.responseText.replace(fetched, '');
    
                //Set the complete response text to be removed next time 
                var fetched=newFetched;
    
                //callback to allow parsing of the fetched data
                callback(lastFetch);
            }
        };
    
        //open and send to begin the stream;
        xhr.open('GET', path, true);
        xhr.send();
    }
    
    parseEvents=function(response){
        var events=[];
        //split out by line break
        var lines=response.split("\n");
    
        //loop through the lines
        for(var i=0;i<lines.length;i++){
    
            //each event consists of 2 lines, one begins with
            //"name:", the other with "data"
            //if we hit data, process it and the previous line
            if(lines[i].substr(0, lines[i].indexOf(':'))=='data'){
    
                //add this event to our list for return
                events.push({
    
                   //get the event name
                   name: lines[i-1].split(':')[1].trim(),
                   //parse the event data
                   data: $.parseJSON(lines[i].substr(lines[i].indexOf(':')+1).trim())
                });
            }
        }
        //return the parsed events
        return events;
    };
    
    evenStream('http://example.com/myEventPath', function(response){
        var events=parseEvents(response);
    });
    

    【讨论】:

      【解决方案4】:

      感谢上面的用户 tothemario 提供我需要弄清楚的线索。

      您似乎可以使用自定义类型将事件发送回浏览器,但为了触发 MESSAGE 事件,您必须将侦听器分配给新类型而不是 message 类型。

      如果您查看下面的客户端代码,它可能会有所说明。

      对于上下文,我的服务器发送一个自定义类型为CustomType 的事件。因此,我为该类型订阅了一个事件侦听器,并为 message 添加了另一个侦听器,作为其他所有内容的全部捕获。

      在此工作流程中,带有CustomType 的浏览器会触发一个不同侦听器的事件。

       <script type="text/javascript">
          var CustomTypeList = [];
      
          function EventSystemOpen(e) {
              console.log("EventSystemOpen", e);
          }
      
          function EventSystemError(e) {
              console.log("EventSystemOpen", e);
              if (e.readyState == EventSource.CLOSED) {
                  //
              }
          }
      
          function GotServerEventMessage(e) {
              console.log("GotServerEventMessage", e);
          }
      
          function GotCustomType(e) {
              CustomTypeList.push(JSON.parse(e.data));
              console.log("Added CustomType", e, JSON.parse(e.data), CustomTypeList);
          }
      
          if (!!window.EventSource) {
              var source = new EventSource('api/listen');
              source.addEventListener('open', EventSystemOpen, false);
              source.addEventListener('error', EventSystemError, false);
              source.addEventListener('message', GotServerEventMessage, false);
              source.addEventListener('CustomType', GotCustomType, false);
          }
       </script>
      

      【讨论】:

        【解决方案5】:

        您可以像这样简单地使用onmessage

        const evtSource = new EventSource("ssedemo.php");
        evtSource.onmessage = function(event) {
           console.log("event " + event.data);
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2016-08-11
          • 1970-01-01
          • 2018-06-29
          • 2014-01-10
          • 1970-01-01
          • 2021-10-19
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多