HTML5 EventSource для всех событий?
У меня есть push-уведомления в моем клиентском приложении JavaScript с помощью EventSource.
Я могу присоединить слушателей событий следующим образом:
source.addEventListener('my_custom_event_type', function(e) {
console.log(e.data);
}, false);
Но я хочу отслеживать все события, которые выталкиваются с сервера (в основном для отладки), поэтому, если какое-то событие отправлено, но у него нет прослушивателя событий, я могу легко его найти. Я имею в виду, я не хочу просто "игнорировать" все события, которые не привязаны к событиям.
Я бы ожидал сделать что-то вроде этого:
source.addEventListener('*', function(e) {
console.debug('Event with no listener attached: ', e);
}, false);
Но спецификация и учебные пособия, подобные тем, которые были у html5rocks, не указывают, возможно ли это или нет.
С другой стороны, это может быть некоторое расширение firefox/chrome, которое позволяет отслеживать все события сервера или что-то в этом роде. Эти вещи действительно помогут в разработке push-уведомлений.
Спасибо!
Ответы
Ответ 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');
Теперь у меня есть компонент, который легко обрабатывать, расширять, отлаживать и тестировать.
Ответ 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
пользователя tothemario
выше за подсказку, которая мне понадобилась, чтобы понять это.
Похоже, что вы МОЖЕТЕ отправить события обратно в браузер с пользовательским типом, но чтобы вызвать событие MESSAGE, вы должны назначить слушателя новому типу, а не типу message
.
Если вы посмотрите на код на стороне клиента, приведенный ниже, мы надеемся проиллюстрировать это.
Для контекста мой сервер отправляет событие с пользовательским типом CustomType
. Поэтому я подписываюсь на прослушиватель событий этого типа и добавляю еще один прослушиватель для message
в качестве перехвата всего остального.
В этом CustomType
процессе CustomType
событие, которое поступает в браузер с 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>