Hvordan lage et sanntidssporteringsprogram ved hjelp av Node.js

Hva du skal skape

I dagens artikkel skal jeg demonstrere hvordan man lager et webapplikasjon som vil vise live-partitur fra NHL. Resultatene oppdateres automatisk når spillene utvikler seg.

Dette er en veldig spennende artikkel for meg, da det gir meg sjansen til å bringe to av mine favorittpassioner sammen: utvikling og sport.

Teknologiene som skal brukes til å lage applikasjonen, er:

  1. node.js
  2. Socket.io
  3. MySportsFeed.com

Hvis du ikke har Node.js installert, kan du gå til nedlastingssiden nå og sette opp den før du fortsetter.

Hva er Socket.io?

Socket.io er en teknologi som forbinder en klient til en server. I dette eksemplet er klienten en nettleser, og serveren er programmet Node.js. Serveren kan ha flere klienter koblet til den til enhver tid.

Når forbindelsen er etablert, kan serveren sende meldinger til alle klientene eller en enkelt klient. Til gjengjeld kan klienten sende en melding til serveren, slik at det muliggjør toveis kommunikasjon i sanntid.

Før Socket.io, vil webapplikasjoner vanligvis bruke AJAX, og både klienten og serveren vil undersøke hverandre på jakt etter hendelser. For eksempel vil hvert tiende sekund et AJAX-anrop oppstå for å se om det var noen meldinger å håndtere.

Polling for meldinger forårsaket en betydelig sum overhead på både klienten og serveren som det ville være konstant på jakt etter meldinger når det ikke var noen.

Med Socket.io mottas meldinger øyeblikkelig uten å måtte søke etter meldinger, redusere overhead.

Sample Socket.io Application

Før vi forbruker sanntids sportsdata, la oss lage et eksempelprogram for å demonstrere hvordan Socket.io fungerer.

For å begynne, skal jeg lage en ny Node.js-applikasjon. I et konsollvindu skal jeg navigere til C: \ GitHub \ NodeJS, lage en ny mappe for søknaden min, og opprett et nytt program:

cd \ GitHub \ NodeJS mkdir SocketExample cd SocketExample npm init

Jeg brukte alle standardinnstillingene.

Fordi vi lager et webprogram, skal jeg bruke en NPM-pakke kalt Express for å forenkle oppsettet. I en ledetekst, installer den som følger: npm installere ekspress - lagre

Og selvfølgelig må vi installere Socket.io-pakken: npm installere socket.io - save

La oss begynne med å opprette webserveren. Opprett en ny fil kalt index.js og legg inn følgende kode i den for å opprette webserveren ved å bruke Express:

var app = krever ('express') (); var http = krever ('http'). Server (app); app.get ('/', funksjon (req, res) res.sendFile (__ dirname + '/index.html');); http.listen (3000, funksjon () console.log ('HTTP server startet på port 3000'););

Hvis du ikke er kjent med Express, inneholder koden ovenfor Express-biblioteket og oppretter en ny HTTP-server. I dette eksemplet lytter HTTP-serveren på port 3000, f.eks. http: // localhost: 3000. En rute er opprettet på roten av nettstedet "/". Resultatet av ruten returnerer en HTML-fil: index.html.

Før vi lager filen index.html, la vi fullføre serveren ved å sette opp Socket.io. Legg til følgende i index.js-filen din for å opprette Socket-serveren:

var io = krever ('socket.io') (http); io.on ('forbindelse', funksjon (socket) console.log ('Klientforbindelse mottatt'););

På samme måte som Express, begynner koden ved å importere Socket.io-biblioteket. Dette er lagret i en variabel som kalles io. Deretter bruker du io variabel, en hendelsehandler er opprettet med funksjon. Hendelsen som blir lyttet til er tilkobling. Denne hendelsen kalles hver gang en klient kobles til serveren.

La oss nå lage vår svært grunnleggende klient. Opprett en ny fil kalt index.html og legg inn følgende kode i:

   Socket.IO Eksempel      

HTML-koden laster inn Socket.io-klienten JavaScript og initierer en forbindelse til serveren. For å se eksemplet, start ditt Node-program: node index.js

Deretter, i nettleseren din, naviger til http: // localhost: 3000. Ingenting vil vises på siden; Men hvis du ser på konsollen der nodeprogrammet kjører, logges to meldinger:

  1. HTTP-server startet på port 3000
  2. Klientforbindelse mottatt

Nå som vi har en vellykket stikkforbindelse, la oss sette den til bruk. La oss begynne med å sende en melding fra serveren til klienten. Da, når klienten mottar meldingen, kan den sende et svar tilbake til serveren.

La oss se på den forkortede index.js-filen:

io.on ('connection', funksjon (socket) console.log ('Klienttilkobling mottatt'); socket.emit ('sendToClient', hei: 'world'); socket.on ('receivedFromClient' (data) console.log (data);););

Den forrige io.on funksjonen er oppdatert for å inkludere noen nye kodelinjer. Den første, socket.emit, sender meldingen til klienten. De sendToClient er navnet på arrangementet. Ved å navngi hendelser kan du sende forskjellige typer meldinger, slik at klienten kan tolke dem annerledes. Det andre tillegget er socket.on, som også inneholder et eventnavn: receivedFromClient. Dette skaper en funksjon som aksepterer data fra klienten. I dette tilfellet blir dataene logget inn i konsollvinduet.

Det fullfører server-side endringer; det kan nå sende og motta data fra eventuelle tilkoblede klienter.

La oss fullføre dette eksemplet ved å oppdatere klienten for å motta sendToClient begivenhet. Når den mottar arrangementet, kan den svare med receivedFromClient hendelse tilbake til serveren.

Dette er oppnådd i JavaScript-delen av HTML-koden, så i index.html-filen har jeg oppdatert JavaScript på følgende måte:

var socket = io (); socket.on ('sendToClient', funksjon (data) console.log (data); socket.emit ('receivedFromClient', min: 'data';;);

Ved hjelp av instantiated socket variabelen, har vi veldig lignende logikk på serveren med en socket.on funksjon. For klienten lytter den til sendToClient begivenhet. Så snart klienten er koblet, sender serveren denne meldingen. Når klienten mottar den, er den logget på konsollen i nettleseren. Klienten bruker deretter det samme socket.emit at serveren pleide å sende den opprinnelige hendelsen. I dette tilfellet sender klienten tilbake receivedFromClient hendelse til serveren. Når serveren mottar meldingen, er den logget inn i konsollvinduet.

Prøv det selv. Først, i en konsoll, kjør knuteprogrammet ditt: node index.js. Legg deretter inn http: // localhost: 3000 i nettleseren din.

Sjekk nettleserkonsollen, og du bør se følgende JSON-data logget: Hei Verden"

Deretter skal du se følgende i kommandoprompten der nodeprogrammet kjører:

HTTP-server startet på port 3000 Kundeforbindelse mottatt min: 'data'

Både klienten og serveren kan bruke JSON-dataene som mottas for å utføre bestemte oppgaver. Vi vil lære mer om det når vi kobler til sanntids sportsdata.

Idrettsdata

Nå som vi har mestret hvordan du sender og mottar data til og fra klienten og serveren, kan dette brukes til å gi oppdateringer i sanntid. Jeg valgte å bruke sportsdata, selv om samme teori ikke er begrenset til sport. Før jeg begynte dette prosjektet, undersøkte jeg ulike idrettsdata. Den jeg bestemte meg for, fordi de tilbyr gratis utviklerkontoer, var MySportsFeeds (jeg er ikke tilknyttet dem på noen måte). For å få tilgang til sanntidsdataene, registrerte jeg meg for en konto og gjorde en liten donasjon. Bidrag starter på $ 1 for å få data oppdatert hvert 10. minutt. Dette vil være bra for eksemplet.

Når kontoen din er konfigurert, kan du fortsette å sette opp tilgang til APIen sin. For å hjelpe med dette, skal jeg bruke deres NPM-pakke: npm installere mysportsfeeds-node --save

Etter at pakken er installert, kan API-anrop gjøres på følgende måte:

var MySportsFeeds = krever ("mysportsfeeds-node"); var msf = nye MySportsFeeds ("1.2", true); msf.authenticate ("********", "*********"); var idag = ny dato (); msf.getData ('nhl', '2017-2018-vanlig', 'resultattavle', 'json', fordate: today.getFullYear () + ('0' + parseInt (today.getMonth () + 1)). skive (-2) + ('0' + today.getDate ()). skive (-2), kraft: true);

I eksemplet ovenfor må du passe på å erstatte anropet til godkjenningsfunksjonen med brukernavnet og passordet ditt.

Følgende kode utfører en API-samtale for å få NHL-resultattavlen for i dag. De fordate variabel er det som spesifiserer i dag. Jeg har også satt makt til ekte slik at et svar alltid blir returnert, selv om dataene ikke er endret.

Med det nåværende oppsettet blir resultatene av API-anropet skrevet til en tekstfil. I det siste eksemplet vil dette bli endret; For demonstrasjonsformål kan resultatfilen imidlertid bli gjennomgått i en tekstredigerer for å forstå innholdet i svaret. Resultatene inneholder et resultattavleobjekt. Dette objektet inneholder en oppringt gruppe gameScore. Dette objektet lagrer resultatet av hvert spill. Hver gjenstand inneholder et barnobjekt som heter spill. Dette objektet gir informasjon om hvem som spiller.

Utenfor spillobjektet er det en håndfull variabler som gir dagens tilstand av spillet. Dataene endres basert på spillets tilstand. For eksempel, når spillet ikke har startet, er det bare noen få variabler som forteller oss at spillet ikke er i gang og ikke har startet.

Når spillet pågår, er det gitt ytterligere data om poengsummen, hvilken periode spillet er i, og hvor mye tid som gjenstår. Vi ser dette i aksjon når vi kommer til HTML for å vise spillet i neste avsnitt.

Real-Time oppdateringer

Vi har alle brikkene til puslespillet, så det er nå på tide å sette puslespillet sammen for å avsløre det endelige bildet. For tiden har MySportsFeeds begrenset støtte for å skape data til oss, så vi må avspore dataene fra dem. Heldigvis vet vi at dataene bare endres en gang hvert 10. minutt, slik at vi ikke trenger å legge til overhead ved polling for endringer for ofte. Når vi har pollet dataene fra dem, kan vi skyve de oppdateringene fra serveren til alle klienter som er tilkoblet.

For å utføre avstemningen, vil jeg bruke JavaScript setInterval funksjon å ringe API (i mitt tilfelle) hvert 10. minutt for å lete etter oppdateringer. Når dataene er mottatt, sendes en hendelse til alle de tilkoblede klientene. Når klientene mottar arrangementet, blir spillresultatene oppdatert med JavaScript i nettleseren.

MySportsFeeds blir også kalt når Nodeprogrammet først starter. Disse dataene vil bli brukt til alle klienter som forbinder før det første 10-minutters intervallet. Dette er lagret i en global variabel. Den samme globale variabelen blir oppdatert som en del av intervallvalsingen. Dette vil sikre at når noen nye kunder kobler seg etter avstemningen, vil de få de nyeste dataene.

For å hjelpe til med noen kode renslighet i hovedindex.js-filen, har jeg opprettet en ny fil kalt data.js. Denne filen inneholder en funksjon som eksporteres (tilgjengelig i index.js-filen) som utfører forrige anrop til MySportsFeeds API. Her er hele innholdet i den filen:

var MySportsFeeds = krever ("mysportsfeeds-node"); var msf = nye MySportsFeeds ("1.2", true, null); msf.authenticate ("*******", "******"); var idag = ny dato (); exports.getData = function () return msf.getData ('nhl', '2017-2018-regular', 'resultattavle', 'json', fordate: today.getFullYear () + ('0' + parseInt .getMonth () + 1)) skive (-2) + ('0' + today.getDate ()). skive (-2), kraft: true); ;

EN GetData funksjonen eksporteres og returnerer resultatet av samtalen, som i dette tilfellet er et løfte som vil bli løst i hovedapplikasjonen.

La oss nå se på det endelige innholdet i index.js-filen:

var app = krever ('express') (); var http = krever ('http'). Server (app); var io = krever ('socket.io') (http); var data = krever ('. / data.js'); // Global variabel for å lagre de nyeste NHL-resultatene var sisteData; // Last NHL-dataene for når klientens første tilkobling // Dette blir oppdatert hvert 10. minutt data.getData (). Deretter ((resultat) => latestData = result;); app.get ('/', funksjon (req, res) res.sendFile (__ dirname + '/index.html');); http.listen (3000, funksjon () console.log ('HTTP server startet på port 3000');); io.on ('tilkobling', funksjon (socket) // når klienter kobler til, send siste datasocket.emit ('data', latestData);); // oppdatere datasettInterval (funksjon () data.getData (). da ((resultat) => // Oppdater siste resultater for når ny klient kobler latestData = result; // send det til alle tilkoblede klienter io.emit ( 'data', resultat); console.log ('Sist oppdatert:' + ny dato ()););, 300000);

De første syv kodelinjene ovenfor overfører de nødvendige biblioteker og det globale latestData variabel. Den endelige listen over biblioteker som brukes er: Express, Http Server opprettet med Express, Socket.io og den nevnte data.js-filen som nettopp er opprettet.

Med nødvendighetene tatt vare på, fyller applikasjonen latestData for klienter som vil koble seg når serveren startes først:

// Global variabel for å lagre de nyeste NHL-resultatene var sisteData; // Last NHL-dataene for når klientens første tilkobling // Dette blir oppdatert hvert 10. minutt data.getData (). Deretter ((resultat) => latestData = result;);

De neste linjene oppretter en rute for rotsiden til nettstedet (http: // localhost: 3000 /) og starter HTTP-serveren for å lytte på port 3000.

Deretter er Socket.io satt opp for å se etter tilkoblinger. Når en ny tilkobling er mottatt, sender serveren en hendelse som heter data med innholdet i latestData variabel.

Og til slutt oppretter den siste delen av koden avstemningsintervallet. Når intervallet oppstår, vil latestData variabelen er oppdatert med resultatene fra API-anropet. Disse dataene avgir deretter samme datahendelse til alle klienter.

// oppdatere datasettInterval (funksjon () data.getData (). da ((resultat) => // Oppdater siste resultater for når ny klient kobler latestData = result; // send det til alle tilkoblede klienter io.emit ( 'data', resultat); console.log ('Sist oppdatert:' + ny dato ()););, 300000);

Det kan hende du oppdager at når klienten kobles til og en hendelse blir sendt, sender den hendelsen ut med kontakten. Denne tilnærmingen vil bare sende hendelsen til den tilkoblede klienten. Inne i intervallet, den globale io brukes til å avgi hendelsen. Dette vil sende arrangementet til alle klienter.

Det fullfører serveren. La oss jobbe på klientens forkant. I et tidligere eksempel opprettet jeg en grunnleggende index.html-fil som satt opp klientforbindelsen som ville logge hendelser fra serveren og sende en tilbake. Jeg skal utvide den filen for å inneholde det fullførte eksemplet.

Fordi serveren sender oss et JSON-objekt, skal jeg bruke jQuery og utnytte en jQuery-utvidelse kalt JsRender. Dette er et templerende bibliotek. Det vil tillate meg å lage en mal med HTML som vil bli brukt til å vise innholdet i hvert NHL-spill på en enkel måte å bruke. I et øyeblikk ser du kraften til dette biblioteket. Den endelige koden er over 40 linjer med kode, så jeg skal bryte den ned i mindre biter, og deretter vise full HTML sammen på slutten.

Denne første delen lager malen som vil bli brukt til å vise spilldataene:

Malen er definert ved hjelp av en skriptetikett. Den inneholder iden til malen og en spesiell skripttype som heter tekst / x-jsrender. Malen definerer en container div for hvert spill som inneholder et klassespill for å bruke noen grunnleggende styling. Innenfor denne div begynner templeringen.

I neste div vises bort og hjemmelaget. Dette gjøres ved å sammenkoble byen og lagnavnet sammen fra spillobjektet fra MySportsFeed-dataene.

: Game.awayTeam.City er hvordan jeg definerer et objekt som vil bli erstattet med en fysisk verdi når malen blir gjengitt. Denne syntaksen er definert av JsRender-biblioteket.

Når lagene er vist, gjør den neste koden av kode noen betinget logikk. Når spillet er uspilte, en streng vil bli utgitt at spillet starter på :spilletid.

Når spillet ikke er fullført, vises nåværende poeng: Nåværende poeng: : awayScore - : homeScore. Og til slutt, litt vanskelig logikk for å identifisere hvilken periode hockeyspillet er i, eller om det er i pause.

Hvis variabelen currentIntermission er gitt i resultatene, så bruker jeg en funksjon jeg definerte kalt ordinal_suffix_of, som vil konvertere perioden til å lese: 1. (2., 3., etc.) Innlevering.

Når det ikke er i pause, ser jeg etter nåværende periode verdi. Dette bruker også ordinal_suffix_of  å vise at spillet er i 1. (2., 3., etc.) periode.

Under dette, en annen funksjon jeg definerte kalt tid igjen brukes til å konvertere antall sekunder som gjenstår i antall minutter og sekunder som gjenstår i perioden. For eksempel: 10:12.

Den endelige delen av koden viser sluttresultatet fordi vi vet at spillet har fullført.

Her er et eksempel på hvordan det ser ut når det er en blanding av ferdige spill, spill i gang og spill som ikke har startet ennå (jeg er ikke en veldig god designer, så det ser ut som du ville forvente når en utvikler lager sitt eget brukergrensesnitt).

Neste opp er en del av JavaScript som lager stikkontakten, hjelperen hjelper ordinal_suffix_of og tid igjen, og en variabel som refererer til jQuery-malen som er opprettet.

Det endelige stykket kode er koden for å motta sokkelhendelsen og gjengi malen:

socket.on ('data', funksjon (data) console.log (data); $ ('# data'). html (tmpl.render (data.scoreboard.gameScore, helpers)););

Jeg har en plassholder div med data-ID. Resultatet av malutgivelsen (tmpl.render) skriver HTML-en til denne beholderen. Det som virkelig er pent er at JsRender-biblioteket kan akseptere en rekke data, i dette tilfellet data.scoreboard.gameScore, som deterer gjennom hvert element i arrayet og lager ett spill per element.

Her er den endelige HTML og JavaScript alt sammen:

   Socket.IO Eksempel   

Start nodeprogrammet og bla til http: // localhost: 3000 for å se resultatene for deg selv!

Hvert X-minutt sender serveren en hendelse til klienten. Klienten vil omdøpe spillelementene med de oppdaterte dataene. Så når du forlater nettstedet åpent og med jevne mellomrom ser på det, vil du se spilldataoppdateringen når spill er i gang.

Konklusjon

Det endelige produktet bruker Socket.io til å opprette en server som klienter kobler til. Serveren henter data og sender den til klienten. Når klienten mottar dataene, kan den sømløst oppdatere skjermen. Dette reduserer belastningen på serveren fordi klienten bare utfører arbeid når den mottar en hendelse fra serveren.

Stikkontakter er ikke begrenset til en retning; klienten kan også sende meldinger til serveren. Når serveren mottar meldingen, kan den utføre litt behandling.

Chat-applikasjoner vil vanligvis fungere på denne måten. Serveren vil motta en melding fra klienten og deretter sendes til alle tilkoblede klienter for å vise at noen har sendt en ny melding.

Forhåpentligvis likte du denne artikkelen som jeg hadde en blast å skape denne sanntids sportsapplikasjonen for en av mine favorittsporter!