On Github justinribeiro / jquery-conf-san-diego-2014-slidedeck
Justin Ribeiro justin@stickmanventures.com
@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
Does this data need to update the DOM? Can I batch it with other updates? Should I be holding that DOM element for later? What's my reflow look like?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.