Cum se face o aplicație în timp real în sport utilizând Node.js

Ce veți crea

În articolul de astăzi voi demonstra cum să faceți o aplicație web care va afișa scoruri live de la NHL. Scorurile se vor actualiza automat odată cu evoluția jocurilor.

Acesta este un articol foarte interesant pentru mine, deoarece îmi permite să îmi aduc două pasiuni preferate: dezvoltarea și sportul.

Tehnologiile care vor fi utilizate pentru a crea aplicația sunt:

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

Dacă nu aveți instalat Node.js, vizitați pagina de descărcare acum și configurați-o înainte de a continua.

Ce este Socket.io?

Socket.io este o tehnologie care conectează un client la un server. În acest exemplu, clientul este un browser web și serverul este aplicația Node.js. Serverul poate avea mai mulți clienți conectați la el în orice moment.

Odată ce conexiunea a fost stabilită, serverul poate trimite mesaje tuturor clienților sau unui client individual. În schimb, clientul poate trimite un mesaj către server, permițând comunicarea bidirecțională în timp real.

Înainte de Socket.io, aplicațiile web ar folosi în mod obișnuit AJAX, iar atât clientul, cât și serverul ar sondaj reciproc în căutarea evenimentelor. De exemplu, la fiecare 10 secunde s-ar întâmpla un apel AJAX pentru a vedea dacă există mesaje care să poată fi rezolvate.

Interogarea mesajelor a cauzat o cantitate semnificativă de cheltuieli atât pe client, cât și pe server, deoarece ar fi în căutarea constantă a mesajelor atunci când nu exista.

Cu Socket.io, mesajele sunt primite instantaneu, fără a fi nevoie să căutați mesaje, reducând cheltuielile generale.

Sample Application Socket.io

Înainte de a consuma date sportive în timp real, să creăm o aplicație de exemplu pentru a demonstra modul în care funcționează Socket.io.

Pentru început, am de gând să creez o nouă aplicație Node.js. Într-o fereastră de consolă, o să navighez la C: \ GitHub \ NodeJS, să creez un nou dosar pentru aplicația mea și să creez o nouă aplicație:

cd \ GitHub \ NodeJS mkdir SocketExemplu cd SocketExemplu npm init

Am folosit toate setările implicite.

Pentru că facem o aplicație web, folosesc un pachet NPM numit Express pentru a simplifica configurarea. Într-un prompt de comandă, instalați-l după cum urmează: npm install express - salvați

Desigur, va trebui să instalăm pachetul Socket.io: npm instala socket.io - salva

Să începem prin crearea serverului web. Creați un fișier nou numit index.js și plasați următorul cod în el pentru a crea serverul web folosind Express:

var app = necesită ('express') (); var http = necesită ("http"). Server (app); app.get ('/', funcția (req, res) res.sendFile (__ dirname + '/ index.html');); http.listen (3000, funcția () console.log ('serverul HTTP a pornit pe portul 3000'););

Dacă nu sunteți familiarizat cu Express, exemplul de cod de mai sus include biblioteca Express și creează un nou server HTTP. În acest exemplu, serverul HTTP ascultă pe portul 3000, de ex. http: // localhost: 3000. O ruta este creata la radacina site-ului "/". Rezultatul rutei returnează un fișier HTML: index.html.

Înainte de a crea fișierul index.html, terminăm serverul instalând Socket.io. Adăugați următoarele în fișierul index.js pentru a crea serverul Socket:

var io = cer ('socket.io') (http); io.on ("conexiune", funcție (socket)) console.log ("Conectare client primită"););

Similar cu Express, codul începe prin importarea bibliotecii Socket.io. Aceasta este stocată într-o variabilă numită io. Apoi, folosind io variabil, este creat un handler de evenimente cu pe funcţie. Evenimentul pentru care a fost ascultat este conexiunea. Acest eveniment se numește de fiecare dată când un client se conectează la server.

Să ne creăm acum clientul nostru de bază. Creați un fișier nou numit index.html și plasați următorul cod în:

   Socket.IO Exemplu      

HTML-ul de mai sus incarca JavaScript-ul clientului Socket.io si initializeaza o conexiune la server. Pentru a vedea exemplul, porniți aplicația Nod: nod index.js

Apoi, în browser-ul dvs., navigați la http: // localhost: 3000. Nimic nu va apărea pe pagină; cu toate acestea, dacă vă uitați la consola în care rulează aplicația Nod, sunt înregistrate două mesaje:

  1. Serverul HTTP a pornit pe portul 3000
  2. Clientul a primit conexiunea

Acum, că avem o conexiune de socket de succes, hai să o folosim. Să începem prin trimiterea unui mesaj de la server către client. Apoi, atunci când clientul primește mesajul, acesta poate trimite un răspuns înapoi la server.

Să ne uităm la fișierul index.js abreviat:

io.on ('conexiune', functie (socket) console.log ('conexiune client primit'); socket.onit ('receiveFromClient' (date) console.log (date);););

Anteriorul io.on funcția a fost actualizată pentru a include câteva linii noi de cod. Primul, socket.emit, trimite mesajul către client. sendToClient este numele evenimentului. Prin denumirea evenimentelor, puteți trimite diferite tipuri de mesaje astfel încât clientul să le poată interpreta diferit. A doua adăugare este socket.on, care conține, de asemenea, un nume de eveniment: receivedFromClient. Aceasta creează o funcție care acceptă date de la client. În acest caz, datele sunt înregistrate în fereastra consolei.

Aceasta completează modificările de la server; acesta poate trimite și primi date de la orice client conectat.

Să terminăm acest exemplu prin actualizarea clientului pentru a primi sendToClient eveniment. Când primește evenimentul, poate răspunde cu receivedFromClient eveniment înapoi la server.

Acest lucru se realizează în partea JavaScript a codului HTML, deci în fișierul index.html, am actualizat JavaScript după cum urmează:

var socket = io (); socket.on ('sendToClient', funcția (date) console.log (data); socket.emit ('receivedFromClient', my: 'data'););

Folosind variabila socket instanțiată, avem o logică foarte asemănătoare pe server cu a socket.on funcţie. Pentru client, acesta ascultă sendToClient eveniment. Imediat ce clientul este conectat, serverul trimite acest mesaj. Când clientul îl primește, este înregistrat în consola din browser. Clientul folosește același lucru socket.emit pe care serverul la folosit pentru a trimite evenimentul original. În acest caz, clientul trimite înapoi receivedFromClient eveniment la server. Când serverul primește mesajul, acesta este înregistrat în fereastra consolei.

Încearcă-te pentru tine. Mai întâi, într-o consolă, rulați aplicația Nod: nod index.js. Apoi, încărcați http: // localhost: 3000 în browserul dvs..

Verificați consola browserului web și ar trebui să vedeți următoarele date JSON înregistrate: Salut Lume"

Apoi, în linia de comandă unde rulează aplicația Nod, ar trebui să vedeți următoarele:

Serverul HTTP a început pe portul 3000 Conectarea la client a primit my: 'data'

Atât clientul cât și serverul pot utiliza datele JSON primite pentru a efectua sarcini specifice. Vom afla mai multe despre acest lucru odată ce ne vom conecta la datele sportive în timp real.

Date despre sport

Acum, că am învățat cum să trimitem și să primim date către și de la client și server, acesta poate fi utilizat pentru a furniza actualizări în timp real. Am ales să folosesc date sportive, deși aceeași teorie nu se limitează la sport. Înainte de a începe acest proiect, am cercetat diferite date despre sport. Cel pe care l-am stabilit, pentru că oferă conturi gratuite pentru dezvoltatori, a fost MySportsFeeds (nu sunt afiliat cu nici un fel). Pentru a accesa datele în timp real, am semnat un cont și am făcut apoi o mică donație. Donațiile încep de la 1 USD pentru ca datele să fie actualizate la fiecare 10 minute. Acest lucru va fi bun pentru exemplu.

După configurarea contului, puteți continua să configurați accesul la API-ul acestora. Pentru a ajuta la aceasta, voi folosi pachetul NPM: npm instalează mysportsfeeds-node - salvează

După instalarea pachetului, apelurile API pot fi efectuate după cum urmează:

var MySportsFeeds = necesită ("mysportsfeeds-node"); var msf = MySportsFeeds noi ("1.2", true); msf.authenticate ("********", "*********"); var astăzi = dată nouă (); msf.getData ('nhl', '2017-2018-regular', 'scoreboard', 'json', fordate: today.getFullYear () + ('0' + parseInt (today.getMonth () + 1)). slice (-2) + ('0' + today.getDate ()) slice (-2), forța: true);

În exemplul de mai sus, asigurați-vă că înlocuiți apelul cu funcția de autentificare cu numele de utilizator și parola.

Următorul cod execută un apel API pentru a obține tabloul de bord al NHL pentru ziua de azi. fordate variabilă este ceea ce se specifică astăzi. De asemenea, am stabilit forta la Adevărat astfel încât să se întoarcă întotdeauna un răspuns, chiar și atunci când datele nu s-au schimbat.

Cu configurarea actuală, rezultatele apelului API sunt scrise într-un fișier text. În exemplul final, acest lucru va fi schimbat; cu toate acestea, pentru scopuri demonstrative, fișierul cu rezultatele poate fi revizuit într-un editor de text pentru a înțelege conținutul răspunsului. Rezultatele conțin un obiect de tabloul de bord. Acest obiect conține o matrice numită gameScore. Acest obiect stochează rezultatul fiecărui joc. Fiecare obiect conține un obiect copil numit joc. Acest obiect furnizează informații despre cine joacă.

În afara obiectului jocului, există o serie de variabile care asigură starea actuală a jocului. Modificările datelor se bazează pe starea jocului. De exemplu, atunci când jocul nu a început, există doar câteva variabile care ne spun că jocul nu este în desfășurare și nu a început.

Când jocul este în desfășurare, sunt furnizate date suplimentare despre scor, în ce perioadă se află jocul și cât timp rămâne. Vom vedea acest lucru în acțiune când ajungem la codul HTML pentru a afișa jocul în secțiunea următoare.

Actualizări în timp real

Avem toate piesele puzzle-ului, așa că acum este momentul să punem puzzle-ul împreună pentru a dezvălui imaginea finală. În prezent, MySportsFeeds are un sprijin limitat pentru împingerea datelor către noi, deci va trebui să facem sondaj de date de la ei. Din fericire, știm că datele se schimbă doar o dată la fiecare 10 minute, deci nu este nevoie să adăugăm superiori prin interogare pentru modificări prea frecvente. Odată ce vom analiza datele de la ele, putem împinge acele actualizări de la server la toți clienții conectați.

Pentru a efectua sondajele, voi folosi JavaScript setInterval pentru a apela API (în cazul meu) la fiecare 10 minute pentru a căuta actualizări. Când datele sunt primite, un eveniment este trimis tuturor clienților conectați. Când clienții primesc evenimentul, scorurile jocului vor fi actualizate cu JavaScript în browserul web.

MySportsFeeds va fi de asemenea apelat când prima aplicație Node pornește. Aceste date vor fi folosite pentru toți clienții care se conectează înainte de primul interval de 10 minute. Aceasta este stocată într-o variabilă globală. Aceeași variabilă globală este actualizată ca parte a interpelării intervalului. Acest lucru va asigura că atunci când se vor conecta noi clienți după interogare, aceștia vor avea cele mai recente date.

Pentru a ajuta la o anumită curățenie a codului în fișierul index.js principal, am creat un nou fișier numit data.js. Acest fișier va conține o funcție care este exportată (disponibilă în fișierul index.js) care efectuează apelul anterior la MySportsFeeds API. Iată conținutul integral al fișierului:

var MySportsFeeds = necesită ("mysportsfeeds-node"); var msf = MySportsFeeds noi ("1.2", true, null); msf.authenticate ("*******", "******"); var astăzi = dată nouă ();    latestData = rezultat;); app.get ('/', funcția (req, res) res.sendFile (__ dirname + '/ index.html');); http.listen (3000, funcția () console.log ('serverul HTTP a pornit pe portul 3000');); io.on ("conexiune", functie (socket) // atunci cand clientii se conecteaza, trimite cele mai recente date socket.emit ('data', latestData);); // refresh data setInterval (function () data.getData (), apoi ((rezultat) => // Actualizați ultimele rezultate pentru conectarea noului client ultimData = rezultat; // trimiteți-l tuturor clienților conectați io.emit ( 'data', rezultat); console.log ('Ultima actualizare:' + new Date ()););, 300000);

Primele șapte linii de cod de mai sus concretizează bibliotecile necesare și globale latestData variabil. Lista finală a bibliotecilor utilizate este: Express, serverul Http creat cu Express, Socket.io și fișierul data.js menționat anterior..

Având în vedere necesitățile luate în considerare, cererea folosește latestData pentru clienții care se vor conecta la pornirea serverului:

// variabila globala pentru a stoca ultimele rezultate NHL var latestData; // Încarcă datele NHL atunci când prima conectare a clientului // Aceasta va fi actualizată la fiecare 10 minute data.getData (), apoi ((rezultat) => latestData = rezultat;);

Următoarele linii creează un traseu pentru pagina principală a site-ului (http: // localhost: 3000 /) și pornesc serverul HTTP pentru a asculta pe portul 3000.

Apoi, Socket.io este configurat pentru a căuta conexiuni. Când se recepționează o nouă conexiune, serverul emite un eveniment numit date cu conținutul latestData variabil.

În final, bucata finală de cod creează intervalul de interogare. Când intervine intervalul, latestData variabila este actualizată cu rezultatele apelului API. Aceste date emite același eveniment de date tuturor clienților.

// refresh data setInterval (function () data.getData (), apoi ((rezultat) => // Actualizați ultimele rezultate pentru conectarea noului client ultimData = rezultat; // trimiteți-l tuturor clienților conectați io.emit ( 'data', rezultat); console.log ('Ultima actualizare:' + new Date ()););, 300000);

Este posibil să observați că atunci când clientul se conectează și un eveniment este emis, acesta emit evenimentul cu variabila socket. Această abordare va trimite evenimentul numai acelui client conectat. În interiorul intervalului, global io este folosit pentru a emite evenimentul. Aceasta va trimite evenimentul tuturor clienților.

Asta termină serverul. Să lucrăm la front-end-ul clientului. Într-un exemplu mai devreme, am creat un fișier index.html de bază care a creat conexiunea client care ar loga evenimentele de pe server și le-a trimis înapoi. Voi extinde acest fișier pentru a conține exemplul completat.

Deoarece serverul ne trimite un obiect JSON, am de gând să folosesc jQuery și să utilizez o extensie jQuery numită JsRender. Aceasta este o bibliotecă templantă. Îmi va permite să creez un șablon cu HTML, care va fi folosit pentru a afișa conținutul fiecărui joc NHL într-un mod ușor de utilizat și consecvent. Într-un moment veți vedea puterea acestei biblioteci. Codul final este de peste 40 de linii de cod, așa că am de gând să-l rupe în jos bucăți mai mici, și apoi afișa integral HTML împreună la sfârșitul.

Această primă parte creează șablonul care va fi utilizat pentru a afișa datele jocului:

Șablonul este definit utilizând o etichetă de script. Acesta conține id-ul șablonului și un tip de script special numit Text / x-jsrender. Șablonul definește un div container pentru fiecare joc care conține un joc de clasă pentru a aplica un stil de bază. În interiorul acestui div, începe templul.

În următorul div, echipa de oaspeți și echipa gazdă sunt afișate. Acest lucru se face prin concatenarea orașului și a numelui echipei, împreună cu obiectul de joc din datele MySportsFeed.

: Game.awayTeam.City este modul în care definim un obiect care va fi înlocuit cu o valoare fizică atunci când șablonul este redat. Această sintaxă este definită de biblioteca JsRender.

Odată ce echipele sunt afișate, următoarea bucată de cod face o anumită logică condiționată. Când jocul este neredate, un șir va fi afișat că jocul va începe la :timp de joc.

Când jocul nu este finalizat, se afișează scorul curent: Scorul actual: : awayScore - : homeScore. Și, în sfârșit, o mică logică dificilă pentru a identifica în ce perioadă este jocul de hochei sau dacă este în pauză.

Dacă variabila currentIntermission este furnizat în rezultate, atunci folosesc o funcție pe care am definit-o numită ordinal_suffix_of, care va converti numărul perioadei de citit: prima (a doua, a treia, etc.) întrerupere.

Când nu este în pauză, eu caut perioada curenta valoare. Aceasta utilizează de asemenea ordinal_suffix_of  pentru a arăta că jocul se află în prima (a doua, a treia, etc.) perioadă.

Sub aceasta, o altă funcție pe care am definit-o timp rămas este folosit pentru a converti numărul de secunde rămase în numărul de minute și secunde rămase în perioadă. De exemplu: 10:12.

Partea finală a codului afișează scorul final deoarece știm că jocul a fost finalizat.

Iată un exemplu de cum arată când există o combinație de jocuri finalizate, jocuri în desfășurare și jocuri care încă nu au început (nu sunt un designer foarte bun, așa că se pare că vă așteptați când un dezvoltator face propriile interfețe de utilizator).

Următorul este o bucată de JavaScript care creează soclul, funcțiile de ajutor ordinal_suffix_of și timp rămas, și o variabilă care face trimitere la șablonul jQuery creat.

Ultima piesă de cod este codul pentru a primi evenimentul socket și a face șablonul:

socket.on ('data', funcția (date) console.log (data); $ ('# data'); html (tmpl.render (data.scoreboard.gameScore, helpers));

Am un div placeholder cu id de date. Rezultatul redării șablonului (tmpl.render) scrie HTML în acest container. Ceea ce este cu adevărat curat este că biblioteca JsRender poate accepta o serie de date, în acest caz data.scoreboard.gameScore, care iterează prin fiecare element din matrice și creează câte un joc pe element.

Aici este codul final HTML și JavaScript toate împreună:

   Socket.IO Exemplu   

Porniți aplicația Nod și căutați http: // localhost: 3000 pentru a vedea rezultatele pentru dvs.!

La fiecare X minute, serverul va trimite un eveniment clientului. Clientul va reprograma elementele jocului cu datele actualizate. Deci, atunci când părăsiți site-ul și deschideți-l periodic, veți vedea reîmprospătarea datelor de joc atunci când jocurile sunt în desfășurare.

Concluzie

Produsul final utilizează Socket.io pentru a crea un server la care se conectează clienții. Serverul preia datele și îl trimite clientului. Când clientul primește datele, acesta poate actualiza fără probleme afișajul. Acest lucru reduce încărcarea pe server, deoarece clientul efectuează o activitate numai atunci când primește un eveniment de la server.

Prizele nu sunt limitate la o singură direcție; clientul poate trimite mesaje și pe server. Când serverul primește mesajul, acesta poate efectua o anumită prelucrare.

Aplicațiile de chat ar funcționa în mod obișnuit în acest fel. Serverul va primi un mesaj de la client și apoi va fi difuzat către toți clienții conectați pentru a arăta că cineva a trimis un mesaj nou.

Sper că vă place acest articol, deoarece am avut o explozie care a creat această aplicație sportivă în timp real pentru unul dintre sporturile mele preferate!

Cod