Justin Ribeiro
[email protected]
@justinribeiro +Justin Ribeiro justinribeiro
Slides: http://goo.gl/tzXnHA
"I've got XHR and it's awesome."
var myServerSentEvent = new EventSource("something.php");
myServerSentEvent.onopen = function () {
// I'm open for business
};
myServerSentEvent.onmessage = function(event){
// Steam me some text
};
myServerSentEvent.onerror = function (event) {
// Call John: ask him to press reset button on rack 2
};
Hey, you said you weren't going to talk about them!
myServerSentEvent.addEventListener("someEventTag", function(event){...});
var myWebSocket = new WebSocket("ws://somewhere");
myWebSocket.onopen = function(event){
// I'm open for business
};
myWebSocket.onclose = function(event){
// what? I closed? What happened?
};
myWebSocket.onmessage = function(event){
// ahhh some data
// I think it's a cat
};
myWebSocket.onerror = function(event){
// no one worries about icebergs
};
myWebSocket.onmessage = function(event){
if(event.data instanceof Blob) {
// an immutable picture of my kids
} else {
// some text describing my kids
}
};
I don't have an immutable, just make it an arraybuffer
myWebSocket.binarytype = "arraybuffer";
myWebSocket.onmessage = function(event){
if(event.data instanceof ArrayBuffer) {
// let's split this buffer up
} else {
// some text describing my kids
}
};
myWebSocket.onmessage = function(event){
if(event.data instanceof ArrayBuffer) {
// known: byte offsets and big-endian
var dataView = new DataView(event.data);
var sensorId = dataView.getUint8(0);
var temp = dataView.getUint16(1);
var lux = dataView.getUint8(3);
}
};
Demo #02: Sensor A1 Reporting ° lx
{
"topic": "office/sensors/a1/out",
"message": {
"degF": 71.9,
"lux": 222.8
}
}
93 bytes. A tiny perfect JSON world.
It's always easy when there's only one.
(93 bytes * 20/second) = 1.8kb.
100 sensors = 180kb a second!
The magical Checklist-O-DOM-update
Bad selectors will ruin you: be specific, cache it, use it
// We'll keep it around for a while
if (!JDR.sensors.cache[topic]) {
var eleName = topic.replace(/\//g, "-");
JDR.sensors.cache[topic] = $("#" + eleName);
JDR.sensors.cache[topic]['o1'] = JDR.sensors.cache[topic].find('.o1');
JDR.sensors.cache[topic]['o2'] = JDR.sensors.cache[topic].find('.o2');
}
This is not a new concept. You should be doing this even if you're not using real time data.
When in need of pure speed, textContent can be your friend.
// We'll keep it around for a while
var myElementToUpdate = $("#glass-timer");
//... WebSocket / EventSource Wire Up
// Update that text!
myElementToUpdate[0].textContent = data.message;
You're updating the DOM, which means it's going to recalc
Limit the scope as much as you can.
/* Layout Boundary for updating Glass stat pack */
#statpack {
left: 10px;
bottom: 10px;
width: 250px;
height: 100px;
overflow: hidden;
position: absolute;
}
Great tool: paullewis/Boundarizr
Great read: Introducing 'layout boundaries'
When #perfmatters you can't be afraid to diverge as needed
By the numbers: JS Perf Test - $.html(), $.text(), textContent
Glass stat pack: from 2.1ms to 0.5ms
Internally used by $.ajax() and $.Deferred() components
Humm, websocket/SSE with $.Deferred() support sounds nice.
Let's do that.
Pretty straight forward
var myBrokerEcho = $.websocket({
url: "ws://echo.websocket.org/"
});
myBrokerEcho.topic( "websocket.onOpen" ).subscribe( myOpenMethod );
myBrokerEcho.topic( "websocket.onMessage" ).subscribe( myMessageMethod );
Pretty straight forward
// ...
ws.connection.onopen = function(event){
ws.topic( "websocket.onOpen" ).publish( event.data );
};
ws.connection.onclose = function(event){
ws.topic( "websocket.onClose" ).publish( event.data );
};
ws.connection.onmessage = function(event){
// ... doing some other stuff
ws.topic( "websocket.onMessage" ).publish( data );
};
ws.topic( "websocket.send" ).subscribe( this.send );
// ...
Internally, it's subscribing to a topic and using it's own method to send back to the open socket.
ws.topic( "websocket.send" ).subscribe( this.send );
How do we send to it?
Let's send some data to the socket!
var myBrokerEcho = $.websocket({
url: "ws://echo.websocket.org/"
});
// Oh it's angry
myBrokerEcho.topic( "websocket.send" ).publish("Send some data");
It's not happy, how do we fix this?
You can't send something to the socket before the open is finished.
myBrokerEcho.topic( "websocket.onOpen" ).subscribe( myOpenMethod );
var dfd = $.Deferred();
var topic = myBrokerEcho.topic( "websocket.send" );
dfd.done( topic.publish );
function myOpenMethod( value ) {
dfd.resolve( "I'm resolved!" );
}
So we create a $.Deferred() and resolve it after open
I've got you covered: jquery.eventsource.callback.js
var myScript = $.eventsource({
url: "sse.php"
});
myScript.topic( "eventsource.onMessage" ).subscribe( onMessage );
function onMessage( value ) {
console.log("Incoming Message!", value);
}
Could use some event channel support
* Approximate: haven't checked his repo today
I am not catching up.