## How-to: Make your application real-time https://hackmd.io/p/parisjs-realtime --- ## We'll invite you to play with us!<br>Get ready to join with your phone or laptop. --- # Join the Demo! https://hackmd.io/parisjs-realtime-demo --- # <i class="fa fa-file-text"></i> HackMD Build community with open collaboration ---- <style> .reveal section img { border: none; background: none; } </style> ![](https://i.imgur.com/H1OLOmh.png =80%x) Techstars backed ---- ## Helping developers to enjoy writing documentations. :100: :book: :books: ---- ## Help open source technologies to build an active developer community. <i class="fa fa-github fa-4x"></i> --- <img src="https://i.imgur.com/PTbB46S.jpg" style="width:300px;height:300px;border-radius:50%"/> ## Max Wu #### CTO of HackMD I love great product and build them.<br>I'm developing my dream with code. --- # What is real-time? Enable users to receive information as soon as it is published by its authors. ---- <!-- .slide: data-background-image="https://i.imgur.com/4uEx1Ho.png" --> ---- ### How fast will you consider it's real-time? 60 FPS makes a smooth video.<!-- .element: class="fragment" data-fragment-index="1" --> **60 frames per second (FPS)**<!-- .element: class="fragment" data-fragment-index="2" --> 1000 millisecond / 60 frames<!-- .element: class="fragment" data-fragment-index="3" --> ~= 16.67 ms/frame ---- <!-- .slide: data-background-image="https://media.giphy.com/media/3owzW5c1tPq63MPmWk/giphy.gif" --> # 16.67 ms # for such a computation ---- ## The average network latency is<br>70 ms ---- <!-- .slide: data-background-image="https://i.imgur.com/dd30BnK.png" --> ---- ### Hard to feel it's real-time if it only shows when data arrives ---- # So you fake it! :stuck_out_tongue_winking_eye: that's what most modern web app does ---- ### Optimistic lock - Show as soon as user inputs it<!-- .element: class="fragment" data-fragment-index="1" --> - Put the operation into buffer and send later<!-- .element: class="fragment" data-fragment-index="2" --> - Rollback if it fails later<!-- .element: class="fragment" data-fragment-index="3" --> --- ## What makes web real-time? - You need to connect network <!-- .element: class="fragment" data-fragment-index="1" --> :stuck_out_tongue_closed_eyes: - So that server can receive your changes<!-- .element: class="fragment" data-fragment-index="2" --> - And other clients are able to receive updates<!-- .element: class="fragment" data-fragment-index="3" --> - Let's see how HTTP works<!-- .element: class="fragment" data-fragment-index="4" --> ---- ## traditional HTTP model 1. client sends request to server<!-- .element: class="fragment" data-fragment-index="1" --> 2. server responses data to client<!-- .element: class="fragment" data-fragment-index="2" --> ---- <!-- .slide: data-background-image="https://i.imgur.com/tYJZNdr.png" --> ---- ## It's one way communication server can't actively push data to client<!-- .element: class="fragment" data-fragment-index="3" --> real-time requires to send updates to client <!-- .element: class="fragment" data-fragment-index="4" --> :cry: <!-- .element: class="fragment" data-fragment-index="4" --> ---- ## long-polling HTTP model 1. client sends request to server<!-- .element: class="fragment" data-fragment-index="1" --> 2. keeps the connection open<!-- .element: class="fragment" data-fragment-index="2" --> 3. client waits until server sends data<!-- .element: class="fragment" data-fragment-index="3" --> ---- <!-- .slide: data-background-image="https://i.imgur.com/yLV2Mim.png" --> ---- ## Still one way communication - But it works!<!-- .element: class="fragment" data-fragment-index="1" --> :triumph: (and for a long time) - HTTP 1.1 is half-duplex, traffic flows only go one direction at a time<!-- .element: class="fragment" data-fragment-index="2" --> - HTTP is stateless, reduntant information sent with every request and response<!-- .element: class="fragment" data-fragment-index="3" --> :tired_face: <!-- .element: class="fragment" data-fragment-index="4" --> ---- ## WebSocket comes to rescue! :thumbsup: :thumbsup: :thumbsup: ---- # WebSocket - bidirectional communication <!-- .element: class="fragment" data-fragment-index="1" --> :tada: - smaller data frame (~1/3 than HTTP) <!-- .element: class="fragment" data-fragment-index="2" --> :package: - lower latency (~4x faster than HTTP) <!-- .element: class="fragment" data-fragment-index="3" --> :zap: [ref.](https://blog.feathersjs.com/http-vs-websockets-a-performance-comparison-da2533f13a77)<!-- .element: class="fragment" data-fragment-index="3" --> ---- <!-- .slide: data-background-image="https://i.imgur.com/vGkUyko.png" --> ---- ### Efficiency | | HTTP | WebSocket | | -------- | -------- | -------- | | Overhead | 100s bytes | 2-6 bytes | | Latency (traditional) | New connection every time | None: use existing connection | | Latency (long-polling) | Time to set up next request | No waiting | <!-- .element: class="fragment" data-fragment-index="1" --> [ref.](https://www.slideshare.net/peterlubbers/html5-real-time-and-websocket/47-WebSocket_Efficiency_HTTP_WebSocketOverhead_100s) <!-- .element: class="fragment" data-fragment-index="1" --> --- ## What can you build with WebSocket? see some examples<!-- .element: class="fragment" data-fragment-index="1" --> ---- ### Collaborative text editor ## <i class="fa fa-file-text"></i> HackMD :sparkles: https://hackmd.io :sparkles: ---- ## `Agar.io` An online multipleplayer game <!-- .slide: data-background-image="https://media.giphy.com/media/kwaJMnc18hDFu/giphy.gif" --> ---- ## <span style="color: black;"> Online chat room</span> https://socketio-chat-example.now.sh/ <!-- .slide: data-background-video="https://i.cloudup.com/transcoded/J4xwRU9DRn.mp4" --> ---- # <i class="fa fa-github"></i> GitHub also uses it to update pages - When other people comment on the issue - When issue has been closed - When pull request have more commits - etc... ---- ### There's always a catch ![](https://i.imgur.com/gPH7VBw.png =800x) https://caniuse.com/#search=websocket --- ## Time for `Socket.IO` :rocket: ---- ## `Socket.IO` :star2: 1. Establishes long-polling connection first<!-- .element: class="fragment" data-fragment-index="1" --> 2. Tries to upgrade to WebSocket transports<!-- .element: class="fragment" data-fragment-index="2" --> 3. If it fails will fallback to use long-polling<!-- .element: class="fragment" data-fragment-index="3" --> Everyone now is happy<!-- .element: class="fragment" data-fragment-index="4" --> :smirk: ---- ## `Socket.IO` :stars: - Intuitive APIs<!-- .element: class="fragment" data-fragment-index="1" --> - Easy to broadcast multiple clients<!-- .element: class="fragment" data-fragment-index="2" --> - Built-in logic for rooms and namespaces<!-- .element: class="fragment" data-fragment-index="3" --> :yellow_heart: <!-- .element: class="fragment" data-fragment-index="4" --> --- ## Let's make a chat room with `Socket.IO` ---- ## Installation <div> Client ```htmlmixed= <script src="/socket.io/socket.io.js"></script> ``` <small>Include `socket.io-client` script in the html.</small> </div> <!-- .element: class="fragment" data-fragment-index="1" --> ---- ## Installation <div> Server ``` npm install --save socket.io ``` <small>Install `socket.io` from npm</small> </div> <!-- .element: class="fragment" data-fragment-index="1" --> <div> ```javascript= const server = require('http').createServer() const io = require('socket.io')(server) server.listen(3000) ``` <small>Create HTTP server and bind with `socket.io` in the node.js app.</small> </div> <!-- .element: class="fragment" data-fragment-index="2" --> ---- ## Client establishes connection ```javascript= const socket = io() ``` <!-- .element: class="fragment" data-fragment-index="1" --> <small>Client tries to connect chat room</small> <!-- .element: class="fragment" data-fragment-index="1" --> ---- ## Server listens on connection ```javascript= io.on('connection', socket => { console.log('a user connected') socket.on('disconnect', () => { console.log('user disconnected') }) }) ``` <!-- .element: class="fragment" data-fragment-index="1" --> <small>Server accepts client connection</small> <!-- .element: class="fragment" data-fragment-index="1" --> ---- ## Server broadcasts to everyone ```javascript= io.emit('room message', 'room is ready') ``` <!-- .element: class="fragment" data-fragment-index="1" --> <small>Server broadcasts room status</small> <!-- .element: class="fragment" data-fragment-index="1" --> ---- ## Client emits event ```javascript= socket.emit('chat message', 'hello world!') ``` <!-- .element: class="fragment" data-fragment-index="1" --> <small>Client emits chat message to room</small> <!-- .element: class="fragment" data-fragment-index="1" --> ---- ## Server listens on event ```javascript= socket.on('chat message', msg => { console.log('message: ' + msg) }) ``` <!-- .element: class="fragment" data-fragment-index="1" --> <small>Server receives the message</small> <!-- .element: class="fragment" data-fragment-index="1" --> ---- ## Server sends to everyone excepts for a certain socket ```javascript= io.on('connection', socket => { socket.on('chat message', msg => { console.log('message: ' + msg) socket.broadcast.emit(msg) }) }) ``` <!-- .element: class="fragment" data-fragment-index="1" --> <small>Server broadcasts chat message to other clients</small> <!-- .element: class="fragment" data-fragment-index="1" --> [read more](https://socket.io/get-started/chat) [emit cheatsheet](https://socket.io/docs/emit-cheatsheet/) <!-- .element: class="fragment" data-fragment-index="1" --> ---- <!-- .slide: data-background-image="https://cdn-images-1.medium.com/max/1600/1*H0mCDTWdcO_rmNZTUI8fmw.jpeg" data-background-size="80%" --> --- ## Server-Sent Events an alternative for sending from server to client ---- ## Server-Sent Events - It's one way - server pushes to client<!-- .element: class="fragment" data-fragment-index="1" --> - Part of HTML5 standard<!-- .element: class="fragment" data-fragment-index="2" --> - Good with HTTP/2 (which is full-duplex)<!-- .element: class="fragment" data-fragment-index="3" --> - Automatic reconnection and event binding<!-- .element: class="fragment" data-fragment-index="4" --> ---- <!-- .slide: data-background-image="https://i.imgur.com/AfmQl7t.png" --> ---- ### There's always a catch, again ![](https://i.imgur.com/vtCKu94.png =800x) <small>Can be easily polyfilled!</small> https://caniuse.com/#search=server%20sent --- ### Comparsion | | HTTP | WebSocket | SSE | | -------- | -------- | -------- | ----- | | Direction | Client to Server | Bidirectional | Server to Client | | Native support | 100% | 90% | 84% | | Overhead | High | Low | Medium | | Latency | 1-2s | < 1s | 1s | <!-- .element: class="fragment" data-fragment-index="1" --> --- ## TL;DR - You can fake the real-time experience - long-polling is the old way to be real-time - WebSocket is the real bidirectional communication - `Socket.IO` is the one for all - Server-Sent Events with HTTP/2 can be an alternative --- # Thanks for listening! Do you have any question? <i class="fa fa-github"></i> <i class="fa fa-twitter"></i> @jackycute <i class="fa fa-file-text"></i> HackMD.io --- ## References - [Why are movies shown in 24fps while 60fps looks more real?](https://www.quora.com/Why-are-movies-shown-in-24fps-while-60fps-looks-more-real) - [An Introduction to WebSockets](https://blog.teamtreehouse.com/an-introduction-to-websockets) - [Engine.IO: the realtime engine](https://github.com/socketio/engine.io#goals) - [What Socket.IO is](https://socket.io/docs/#What-Socket-IO-is) ---- ## References - [Ultra fast applications using Node.js](https://openclassrooms.com/en/courses/2504541-ultra-fast-applications-using-node-js/2505653-socket-io-let-s-go-to-real-time) - [Building a Node.js WebSocket Chat App with Socket.io and React](https://itnext.io/building-a-node-js-websocket-chat-app-with-socket-io-and-react-473a0686d1e1) - [How JavaScript works: Deep dive into WebSockets and HTTP/2 with SSE + how to pick the right path](https://blog.sessionstack.com/how-javascript-works-deep-dive-into-websockets-and-http-2-with-sse-how-to-pick-the-right-path-584e6b8e3bf7) - [Polling vs SSE vs WebSocket— How to choose the right one ](https://codeburst.io/polling-vs-sse-vs-websocket-how-to-choose-the-right-one-1859e4e13bd9)
{"metaMigratedAt":"2023-06-14T19:09:12.361Z","metaMigratedFrom":"YAML","title":"2018/11/28 How-to: Make your application real-time","breaks":true,"disqus":"hackmd","slideOptions":"{\"width\":1000}","contributors":"[{\"id\":\"61af98f4-b303-4819-b08b-aa32cf6677a8\",\"add\":15750,\"del\":3046}]"}
    1860 views