javascript 所有事件的 HTML5 EventSource 侦听器?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9933619/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-26 08:17:23  来源:igfitidea点击:

HTML5 EventSource listener for all events?

javascripthtmlserver-sent-events

提问by tothemario

I have push notifications in my JavaScript client app using EventSource. I can attach event listeners like this:

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

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

But I want to monitor all events that are being pushed from the server (basically for debugging), so if some event is sent but it has no event listener I can easily find it. I mean, I don't want to just "ignore" all events that have no eventListeners binded.

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

I would expect to do something like this:

我希望做这样的事情:

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

But the specification and tutorials like the one at html5rocksdon't specify if this is possible or not.

但是html5rocks 中的规范和教程并没有具体说明这是否可行。

In the other hand, it may be some firefox/chrome extension that allows to monitor all server events or something. Those things would really help on developing push notifications.

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

Thanks!

谢谢!

回答by tothemario

I figure out a solution myself, that also improves tremendously the EventSource interface.

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

Server side: Do not send the event type, just include an additional data field (having that I always use json). So instead of

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

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

I send this from the server instead:

我改为从服务器发送:

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

Client side: Now I can use EventSource onmessage callback, that is fired on every message that does not have an event type.

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

And for bind event listeners, I create a wrapper class with Backbone.Event functionality. The result:

对于绑定事件侦听器,我创建了一个具有 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;
})();

Now with this wrapper class, I can easily extend the functionality, all server sent events can be easily monitored and thanks to extending Backbone.Events the event handling in this class is much more powerful.

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

Usage example:

用法示例:

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');

Now I have a component that is easy to handle, extend, debug and test.

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

回答by gilcierweb

 <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>

回答by Trey

I know this isn't an EventSource, but I was looking for the same thing (a way to catch all incoming events without knowing their type). Without any control over the server sending these events, I ended up just writing it with an XHR, in case anyone else comes across this:

我知道这不是 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);
});

回答by Alex C

Credit to user tothemarioabove for the clue I needed to figure this out.

归功于tothemario上面的用户,我需要弄清楚这一点。

It appears that you CAN send events back to the browser with a custom type, but in order to trigger the MESSAGE event you must assign a listener to the new type rather than the messagetype.

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

If you look at the client side code below it will hopefully illustrate.

如果您查看下面的客户端代码,它有望说明。

For context, my server sends an event with the custom type CustomType. Therefore I subscribe with an event listener to that type, and I add another listener for messageas a catch all for everything else.

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

In this workflow, an event that comes to the browser with the CustomTypea different listener fires.

在此工作流中,将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>