Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Pushing the Web forward.

Pushing the Web forward.

The slides of the presentation I gave at Fronteers 2014. I talked about the old and the now of the real-time web. High lighting the issues and the fixes for most of the common issues.

Arnout Kazemier

October 09, 2014
Tweet

More Decks by Arnout Kazemier

Other Decks in Programming

Transcript

  1. var s = document.createElement("script"); s.src = "https://example.com/resource"; s.async = true;

    var target = document.getElementsByTagName("script")[0]; target.parentNode.insertBefore(s, target); jsonp GET
  2. var i = document.createElement("iframe"); i.name = "posttarget"; i.src = "javascript:0";

    var f = document.createElement("form"); form.action = "https://example.org/resource"; form.target = i.name; var t = document.createElement("textarea"); t.value = "body to post"; t.name = "data"; f.appendChild(i); f.appendChild(t); document.body.appendChild(f); f.submit(); jsonp POST
  3. var xhr = new XDomainRequest(); xhr.open("GET", "http://example.com/resource", true); xhr.onload =

    function () { console.log(xhr.responseText); }; xhr.send(); XDOMAINREQUEST
  4. var i = 0; // // Generate unique URL for

    all GET/POST/PUT/* requests // var unique = +new Date() +":"+ i++; url = url + (~url.indexOf("?") ? "&" : "?") +"t="+ unique; stamp + unique
  5. now

  6. just because its posted on the internet it doesn't mean

    its true chrome should be flagged as partial correction*
  7. GET /chat HTTP/1.1 Host: server.example.com Upgrade: websocket Connection: Upgrade Sec-WebSocket-Key:

    dGhlIHNhbXBsZSBub25jZQ== Origin: http://example.com Sec-WebSocket-Protocol: chat, superchat Sec-WebSocket-Version: 13 The handshake from the server looks as follows: HTTP/1.1 101 Switching Protocols Upgrade: websocket Connection: Upgrade Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo= Sec-WebSocket-Protocol: chat complex but optimized protocol 22,043 words, 01:50:12 reading time
  8. var ws; try { ws = new WebSocket("wss://localhost:8080/"); } catch

    () { return console.error("shit happend", e); } ws.onmessage = function message(event) { console.log(event.data); }; ws.onclose = function close() { console.log(event.data); }; ws.send("Sup Fronteers"); simple and understandable api
  9. var ws; try { ws = new WebSocket("wss://localhost:8080/"); } catch

    () { return console.error("shit happend", e); } ws.binaryType = "arraybuffer"; var image = canvas.getContext("2d").getImageData(0, 0, 440, 300) , data = new Uint8Array(image.data.length); for (var i = 0; i < image.data.length; i++) { data[i] = image.data[i]; } ws.send(data.buffer); binary
  10. HTTP proxy settings in your network settings can cause a

    full browser crash luckly, its mac only
  11. if ( // Target safari browsers $.browser.safari // Not chrome

    && !$.browser.chrome // And correct WebKit version && parseFloat($.browser.version, 0) < 534.54 ) { // Don’t use WebSockets. return; } browser sniffing
  12. Writing to a closed WebSocket connection can crash your phone

    Affects Mobile Safari when returning to the page from a different tab or retrieving Safari from the background
  13. var ws = new WebSocket("wss://localhost:8080/"); ws.onmessage = function message(event) {

    setTimeout(function timeout() { ws.send("pong:"+ event.data); }, 0); }; add a slight delay
  14. var ws = new WebSocket("wss://localhost:8080/"); ws.onmessage = function message(event) {

    // // Wrap sends in a setTimeout out to allow the // readyState to be correctly set to closed. But // Only have this delay on mobile devices. // if (mobile) return setTimeout(function timeout() { ws.send("pong:"+ event.data); }, 0); ws.send("pong:"+ event.data); }; dont introduce pointless latency
  15. $("body").keydown(function (e) { // // make sure that you capture

    the `esc` key and // prevent it's default action from happening. // if (e.which === 27) e.preventDefault(); }); intercept & prevent
  16. var ua = navigator.userAgent.toLowerCase(); // // Detect all possible mobile

    phones to filter out WebSockets // if ( ~ua.indexOf("mobile") || ~ua.indexOf("android") || ~ua.indexOf("ios") // .. and more .. ) { // Don't use WebSockets. } disable if you have fallbacks
  17. HTTP/1.1 200 OK Content-Type: text/event-stream : this is a comment

    data: this triggers the `message` event event: foo data: this triggers the foo event data: and even has 2 lines, still emitted as one id: 1 data: use message ids to retrieve dropped messages retry: 1000 human readable protocol 4,852 words, 00:24:15 reading time
  18. var es = new EventSource("https://example.org/foo/bar"); es.addEventListener("message", function message(evt) { console.log(evt.message);

    }, false); es.addEventListener("error", function close() { console.log(es.readyState); }, false); simple and understandable api
  19. // // Check for CORS support. // "withCredentials" in EventSource.prototype;

    // // And use: // var es = new EventSource(“https://example.org/foo/bar", { withCredentials: true }); cors support
  20. // // Sending using postMessage. // var i = document.createElement("iframe");

    i.src = "https://example.com/iframe"; document.body.appendChild(i); // // Sending using postMessage. // i.contentWindow.postMessage("hello", origin); window.parent.postMessage("world", origin); // // Receiving messages. // window.addEventListener("message", listener, false); document.attachEvent("onmessage", listener); window.attachEvent("onmessage", listener); sauce: http://stevesouders.com/misc/test-postmessage.php iframe hack
  21. var xhr = new XMLHttpRequest(); xhr.open("GET", "/resource", true); xhr.setRequestHeader("Content-Type", "text/plain;charset=UTF8");

    xhr.timeout = 5000; xhr.onreadystatechange = function () { // Process the XHR request }; xhr.send(); prevent CORS Preflight
  22. var interval = 3000 , attempt = 0 , times

    = 10; setTimeout(function reconnect() { attempt++; connect(function (err) { if (attempt === times) return; else if (err) setTimeout(reconnect, interval); }); }, interval); reconnect interval
  23. var maxDelay = Infinity , minDelay = 500 , attempt

    = 0 , times = 10 , factor = 0; function timeout() { return attempt !== 1 ? Math.min(Math.round( (Math.random() + 1) * minDelay * Math.pow(factor, attempt) ), maxDelay) : minDelay; } setTimeout(function reconnect() { attempt++; connect(function (err) { if (attempt === times) return; else if (err) setTimeout(reconnect, timeout()); }); }, timeout()); random back off
  24. var img = document.createElement("img"); img.onerror = function () { console.log("down");

    }; img.onload = function () { console.log("up"); } img.src = "/favicon.ico?t="+ Date.now(); image check
  25. var xhr = new XMLHttpRequest(); xhr.open("HEAD", "/favicon.ico?t="+ Date.now(), true); xhr.timeout

    = 5000; xhr.onreadystatechange = function () { if (xhr.readyState == 0) console.log("down"); else if (xhr.readyState == 4) { if (xhr.status && xhr.status < 12000) console.log("up"); else console.log("down"); } }; xhr.send(); Or even an xhr
  26. var worker = new SharedWorker("/worker.js"); worker.port.addEventListener("message", incoming, false); worker.port.start(); //

    Required for addEventListener. worker.port.postMessage({ can: "send JSON" }); // // worker.js: // var connections = []; self.addEventListener("connect", function connect(e) { var port = e.ports[0]; connections.push(port); }, false); connections.forEach(function each(port) { port.postMessage({ can: "send JSON" }); }); sharedworker
  27. var blob = new Blob([ workercode ], { type: "text/javascript"

    }) , url = URL.createObjectURL(blob) , worker = new SharedWorker(url); worker.port.addEventListener("message", incoming, false); worker.port.start(); // Required for addEventListener. worker.port.postMessage({ can: "send JSON" }); sharedworker , inlined?
  28. window.addEventListener("storage", function storage(e) { console.log(e.key, e.newValue); }, false); try {

    localStorage.setItem("foo", "bar"); } catch (e) { /* Storage full? Unavailable? inPrivate tab? */ } localstorage
  29. var interval = setInterval(function ticktock() { var id = readCookie("id")

    , value = readCookie(id); if (value) { // Process all the datas. } }, 100); // // Behold! // var id = 0; function write(msg) { setCookie("id", "foo"+ id); setCookie("foo"+ id, msg, "300ms"); } polling