[{"data":1,"prerenderedAt":229},["ShallowReactive",2],{"DefaultLayouten":3,"language-blog-slug-real-time-communication-with-server-sent-events-i18n-slugs":134,"language-blog-slug-en-real-time-communication-with-server-sent-events":138},{"app":4,"menu":31,"footer":66},{"githubUrl":5,"youtubeUrl":6,"linkedinUrl":7,"phoneNumber":8,"emailAddress":9,"legal":10,"addresses":20},"https:\u002F\u002Fgithub.com\u002Fvoorhoede\u002F","https:\u002F\u002Fwww.youtube.com\u002Fchannel\u002FUCzHuhQVYFRixtQN2-swcuGg","https:\u002F\u002Fwww.linkedin.com\u002Fcompany\u002Fde-voorhoede","+31 20 2610 954","post@voorhoede.nl",[11,14,17],{"title":12,"value":13},"KvK","56017235",{"title":15,"value":16},"BTW","NL851944620B01",{"title":18,"value":19},"IBAN","NL14TRIO0320142078",[21,26],{"address":22,"city":23,"googleMapsLink":24,"postalCode":25},"Koivistokade 70","Amsterdam","https:\u002F\u002Fwww.google.com\u002Fmaps\u002Fplace\u002FDe+Voorhoede+%7C+Front-end+Development\u002F@52.396847,4.8700823,17z\u002Fdata=!3m1!4b1!4m5!3m4!1s0x47c5e21d502d2d59:0xbf570944a96ebf45!8m2!3d52.347647!4d4.8502154","1013 BB",{"address":27,"city":28,"googleMapsLink":29,"postalCode":30},"Koornmarkt 22","Delft","https:\u002F\u002Fwww.google.nl\u002Fmaps\u002Fplace\u002FKoornmarkt+22,+2611+EG+Delft\u002F@52.0093477,4.3573054,17z\u002F","2611 EG",{"title":32,"callToActions":33,"links":39},"Site Menu",[34],{"id":35,"title":36,"link":37},"163140902","Contact",{"__typename":38},"ContactRecord",[40,46,51,56,61],{"id":41,"title":42,"link":43},"163140904","Impact",{"__typename":44,"slug":45},"PageRecord","impact",{"id":47,"title":48,"link":49},"163140905","Services",{"__typename":50},"ServiceOverviewRecord",{"id":52,"title":53,"link":54},"163140906","Cases",{"__typename":55},"CaseOverviewRecord",{"id":57,"title":58,"link":59},"163140908","About us",{"__typename":44,"slug":60},"about-us",{"id":62,"title":63,"link":64},"d6WdFJq2SOuc3dWtpibbXQ","Work at",{"__typename":44,"slug":65},"work-at",{"links":67,"copyrightTitle":93,"copyrightLabel":94,"copyrightLink":95,"privacyTitle":96,"privacyLabel":97,"privacyLink":98,"certificatesGrid":99},[68,71,74,77,82,85,88],{"id":69,"title":42,"link":70},"144185264",{"__typename":44,"slug":45},{"id":72,"title":48,"link":73},"144185265",{"__typename":50},{"id":75,"title":53,"link":76},"144185266",{"__typename":55},{"id":78,"title":79,"link":80},"144185267","Blog",{"__typename":81},"BlogPostOverviewRecord",{"id":83,"title":58,"link":84},"144185268",{"__typename":44,"slug":60},{"id":86,"title":36,"link":87},"144185269",{"__typename":38},{"id":89,"title":90,"link":91},"144185270","FAQ",{"__typename":44,"slug":92},"faq","Creative Commons licence and disclaimer","CC BY 4.0","https:\u002F\u002Fcreativecommons.org\u002Flicenses\u002Fby\u002F4.0\u002F","De Voorhoede privacy statement (pdf)","Privacy statement","https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1763455455-vh-isms-006-privacy-statement-de-voorhoede-en.pdf",[100,112,123],{"id":101,"image":102,"link":107},"Xq4bBfg_TZ6Fkjax9mkbLQ",{"url":103,"alt":104,"width":105,"height":106},"https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1687353463-b-corp-logo-black-rgb.png","B Corp logo",404,680,{"__typename":108,"id":109,"title":110,"url":111},"ExternalLinkRecord","fGW1ak8XQYaYDLkBSyncog","B Corp","https:\u002F\u002Fwww.bcorporation.net\u002Fen-us\u002Ffind-a-b-corp\u002Fcompany\u002Fde-voorhoede\u002F",{"id":113,"image":114,"link":119},"c5mCXRTiSraRIB25fw1p7Q",{"url":115,"alt":116,"width":117,"height":118},"https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1687353461-dda-boxlogo-black.png","Dutch Digital Agencies logo",627,480,{"__typename":108,"id":120,"title":121,"url":122},"P6Jh7B0cTv2cKyNEeKVWVQ","Dutch Digital Agencies","https:\u002F\u002Fdutchdigitalagencies.com\u002Fleden\u002Fde-voorhoede\u002F",{"id":124,"image":125,"link":129},"MT5SCyNxSTSr_v5eeATMZw",{"url":126,"alt":127,"width":128,"height":128},"https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1775730283-dnv.png","DNV logo",518,{"id":130,"title":131,"link":132},"BRtNB5HnT5i-7HkA8IYzBw","DIV",{"__typename":44,"slug":133},"impact\u002Fdigitale-producten-privacy-by-design",[135],{"locale":136,"value":137},"en","real-time-communication-with-server-sent-events",{"page":139},{"slug":137,"i18nSlugs":140,"social":142,"title":147,"subtitle":79,"isArchived":148,"headerIllustration":149,"date":150,"authors":151,"introTitle":167,"items":168,"pivots":216,"relatedBlogPosts":227,"tags":228,"onMountedScript":154,"onUnmountedScript":154},[141],{"locale":136,"value":137},{"title":143,"description":144,"image":145},"Real-time communication Server Sent Events | De Voorhoede","Creating a streaming connection for text data, from the server to the client.",{"url":146},"https:\u002F\u002Fwww.datocms-assets.com\u002F2850\u002F1516801900-ap_100806131932-e.jpeg","Real-time communication with Server Sent Events",false,null,"2018-01-24T01:00:00.000+01:00",[152,160],{"name":153,"lastName":154,"slug":155,"image":156},"Jesse","","jesse",{"url":157,"alt":149,"width":158,"height":159},"https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1683534636-placeholder.jpg",1235,1646,{"name":161,"lastName":154,"slug":162,"image":163},"Anne","anne",{"url":164,"alt":149,"width":165,"height":166},"https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1683535114-anne.jpg",1823,2431,"Creating a streaming connection for text data, from the server to the client",[169,173,178,182,193,196,199,202,206,209,212],{"__typename":170,"id":171,"title":154,"body":172},"TextSectionRecord","401343","\u003Cp>Sometimes in the land of web development, popularity trumps usefulness. This might be the case for websockets versus server-sent events. While \u003Ca href=\"https:\u002F\u002Fsocket.io\u002F\">socket.io\u003C\u002Fa> became the go-to library for real time communication, Server-sent Events (SSE) is often ignored. Why? Perhaps developers are scared off by the vanilla-ness of SSE! The ease of implementation in both server and browser however, are its great benefits. Let&rsquo;s dive in.\u003C\u002Fp>",{"__typename":174,"id":175,"language":176,"body":177},"CodeBlockRecord","401344","javascript","const express = require('express');\nconst app = express();\n\napp.get('\u002Feventstream', (req, res, next) => {\n\tres.set({\n\t\t'Content-Type': 'text\u002Fevent-stream',\n\t\t'Cache-Control': 'no-cache',\n\t\t'Connection': 'keep-alive'\n\t});\n\tapp.on('message', data => {\n\t\tres.write(`event: message\\n`);\n\t\tres.write(`data: ${JSON.stringify(data)}\\n\\n`);\n\t});\n});",{"__typename":170,"id":179,"title":180,"body":181},"401517","Why real-time communication","\u003Cp>With real-time communication &mdash; instead of requiring the user to refresh their browser &mdash; new information can be appended to a web page instantly. Examples: an arrival &amp; departure table for flights or trains. Remote health monitoring for elderly care. Visualising data like current traffic jams, or emerging topics on news feeds.\u003C\u002Fp>",{"__typename":183,"id":184,"image":185,"caption":190,"fullWidth":191,"captionPosition":192},"ImageRecord","176453177",{"url":186,"alt":187,"width":188,"height":189},"https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1537966189-1516801769-ap100806131932-e.jpeg","Traffic jam on an intersection",990,556,"Real-time-communicate this!",true,"left",{"__typename":170,"id":194,"title":154,"body":195},"401551","\u003Cp>As you can see, the \u003Ccode>eventstream\u003C\u002Fcode> route creates a response with some headers, the most important of which is the \u003Ccode>Content-Type: text\u002Fevent-stream\u003C\u002Fcode> header. This makes sure the response is a continuous stream of text.\u003C\u002Fp>\n\u003Cp>Then, by using Express&rsquo;s built-in event emitter, we listen to the \u003Ccode>message\u003C\u002Fcode>event and write to the response stream. SSE expects the text to send to be in a specific \u003Ca href=\"https:\u002F\u002Fwww.html5rocks.com\u002Fen\u002Ftutorials\u002Feventsource\u002Fbasics\u002F#toc-event-stream-format\">format\u003C\u002Fa>. That explains the newline characters; the \u003Ccode>event\u003C\u002Fcode> and \u003Ccode>data\u003C\u002Fcode> keywords are part of SSE specifications, too.\u003C\u002Fp>\n\u003Cp>Let&rsquo;s say we want to send some data when a message is posted to the server:\u003C\u002Fp>",{"__typename":174,"id":197,"language":176,"body":198},"401552","app.post('\u002Fmessage', (req, res, next) => {\n\tconst message = req.body.message;\n\t\u002F\u002F ...\n\t\u002F\u002F Some code here to handle the message, \n\t\u002F\u002F by saving it in a database for instance\n\t\u002F\u002F ...\n\tapp.emit('message', {\n\t\ttitle: 'New message!',\n\t\tmessage,\n\t\ttimestamp: new Date()\n\t});\n})",{"__typename":170,"id":200,"title":154,"body":201},"401553","\u003Cp>That&rsquo;s it! Whenever a message is posted to the \u003Ccode>\u002Fmessage\u003C\u002Fcode> endpoint, an event will be fired that writes to the event stream. Now all we need to do is pick it up on the client side.\u003C\u002Fp>",{"__typename":170,"id":203,"title":204,"body":205},"401554","Client set-up","\u003Cp>On the client side, we listen to the event stream. This is done with an \u003Ca href=\"https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FAPI\u002FEventSource\">EventSource\u003C\u002Fa> instance (don&rsquo;t forget to \u003Ca href=\"https:\u002F\u002Fgithub.com\u002FYaffle\u002FEventSource\">polyfill for IE\u002FEdge\u003C\u002Fa>!).\u003C\u002Fp>",{"__typename":174,"id":207,"language":176,"body":208},"401880","const evtSource = new EventSource('\u002Feventstream');\nevtSource.addEventListener('message', event => {\n    const data = JSON.parse(event.data);\n        \u002F\u002F\n        \u002F\u002F ...insert magic here!\n        \u002F\u002F\n})",{"__typename":170,"id":210,"title":154,"body":211},"401555","\u003Cp>The \u003Ccode>EventSource\u003C\u002Fcode> instance opens a connection to the endpoint on our server. Whenever new text is added to the event stream, the event listener fires. We parse data from the event object, and from there your app logic takes over. It&rsquo;s that easy.\u003C\u002Fp>\n\u003Cp>So what do you think? Next time you need realtime stuff, why not SSE!\u003C\u002Fp>",{"__typename":170,"id":213,"title":214,"body":215},"401576","Coda","\u003Cp>\u003Cstrong>How about the Push API, you ask?\u003C\u002Fstrong> The bottom line with the Push API is that it needs a service worker. Then again, when you&rsquo;re building a PWA, there is a lot of power in push messages. They are picked up even if the browser app is closed.\u003C\u002Fp>\n\u003Cp>\u003Cstrong>You want SSE, but need binary data?\u003C\u002Fstrong> Let&rsquo;s say you want to send an image: you could use base64 encoding. There is a lot of overhead in bytesize (about a third) though. An alternative would be to send the URI of the image to the client, and fetch it asynchronously. An added benefit: the fetched asset could leverage caching and compression, which a streamed asset can&rsquo;t.\u003C\u002Fp>",[217],{"title":218,"body":219,"links":220,"mailchimpValue":154,"mailchimpName":154,"mailchimpId":154,"formType":154,"contactPerson":149},"Also in love with the web?","\u003Cp>For us, that’s about technology and user experience. Fast, available for all, enjoyable to use. And fun to build. This is how our team bands together, adhering to the same values, to make sure we achieve a solid result for clients both large and small. Does that fit you?\u003C\u002Fp>\n",[221],{"__typename":222,"id":223,"title":224,"link":225},"InternalLinkRecord","163140992","Join our team",{"__typename":44,"slug":226},"jobs",[],[],1776256142992]