Mai multe aplicații cu o singură pagină cu AngularJS & Socket.IO Crearea Bibliotecii

Nici HTML, nici HTTP nu au fost create pentru aplicații web dinamice. În principiu, ne bazăm pe hack-uri, pe hack-uri, pentru a oferi aplicațiilor noastre o interfață de utilizator receptivă. AngularJS elimină unele limitări din HTML, permițându-ne să creăm și să gestionăm mai ușor codul de interfață utilizator. Socket.IO, pe de altă parte, ne ajută să trimitem date de la server nu numai atunci când cere clientul, ci și atunci când serverul are nevoie. În acest articol vă voi arăta cum să combinați aceste două, pentru a îmbunătăți capacitatea de reacție a aplicațiilor dvs. pe o singură pagină.


Introducere

În prima parte a acestui tutorial vom crea un serviciu AngularJS reutilizabil pentru Socket.IO. Din cauza aceasta reutilizabile parte, acest lucru va fi un pic mai complicat decât utilizarea module.service () sau module.factory (). Aceste două funcții sunt doar zahăr sintactic pe partea superioară celei mai joase module.provider () , pe care o vom folosi pentru a oferi câteva opțiuni de configurare. Dacă nu ați mai folosit până acum AngularJS, vă sfătuiesc să urmați cel puțin tutorialul oficial și câteva tutoriale aici pe Tuts+.


Pregătire: Back-End-ul

Înainte de a începe să scriem modulul nostru AngularJS, avem nevoie de un simplu back-end pentru testare. Dacă sunteți deja familiarizat cu Socket.IO, puteți doar să derulați până la capătul acestei secțiuni, să copiați sursa de back-end și să treceți la următoarea, dacă nu - citiți mai departe.

Module necesare

Vom avea nevoie doar de ea socket.io. Puteți să o instalați direct utilizând NPM comanda astfel:

npm instalare socket.io 

Sau creați un package.json fișier, puneți această linie în dependențe secțiune:

"socket.io": "0.9.x" 

Și executați npm install comanda.

Crearea serverului Socket.IO

Deoarece nu avem nevoie de un cadru web complicat, cum ar fi Express, putem crea serverul folosind Socket.IO:

var io = cer ('socket.io') (8080); 

Asta e tot ce aveți nevoie pentru a configura serverul Socket.IO. Dacă porniți aplicația, ar trebui să vedeți o ieșire similară în consola:

Și ar trebui să aveți acces la socket.io.js fișier în browser-ul dvs. la http: // localhost: 8080 / socket.io / socket.io.js:

Manipularea conexiunilor

Ne vom ocupa de toate conexiunile primite în conexiune eveniment ascultător al io.sockets obiect:

io.sockets.on ("conexiune", funcție (socket) ); 

priză atributul trecut la apelul de apel este clientul conectat și putem asculta evenimentele de pe acesta.

Un ascultător de bază

Acum vom adăuga un ascultător de bază în apelul de mai sus. Acesta va trimite datele primite, înapoi la client folosind socket.emit () metodă:

 socket.on ('echo', funcție (date) socket.emit ('echo', date);); 

ecou este numele evenimentului personalizat pe care îl vom folosi ulterior.

Un ascultător cu confirmare

De asemenea, vom folosi recunoștințe în biblioteca noastră. Această caracteristică vă permite să transmiteți o funcție ca al treilea parametru al socket.emit () metodă. Această funcție poate fi apelată pe server pentru a trimite date către client:

 socket.on ('echo-ack', funcție (date, callback) callback (date);); 

Acest lucru vă permite să răspundeți la client fără a fi nevoie să ascultați evenimentele (ceea ce este util dacă doriți doar să solicitați date de la server).

Acum, testul nostru de back-end este complet. Codul ar trebui să arate așa (acesta este codul pe care trebuie să îl copiați dacă ați omis această secțiune):

var io = cer ('socket.io') (8080); io.sockets.on ("conexiune", functie (socket) socket.on ('echo', functie (data) socket.emit ('echo', data); ', funcția (date, callback) callback (date););); 

Acum ar trebui să rulați aplicația și să o lăsați să ruleze înainte de a continua cu restul tutorialului.


Pregătire: Front-End

Vom avea, desigur, nevoie de HTML pentru a testa biblioteca noastră. Trebuie să includem AngularJS, socket.io.js de la back-end-ul nostru unghiulare-socket.js bibliotecă și un controler de bază AngularJS pentru a efectua unele teste. Controlorul va fi inlusit în din documentul de simplificare a fluxului de lucru:

           

Tot ce avem nevoie pentru moment, vom reveni la eticheta goală de script mai târziu, deoarece încă nu avem biblioteca.


Crearea Bibliotecii Socket.IO AngularJS

În această secțiune vom crea unghiulare-socket.js bibliotecă. Tot codul trebuie inserat în acest fișier.

Modulul

Să începem cu crearea modulului pentru lib:

var modul = angular.module ("socket.io", []); 

Nu avem dependențe, așa că matricea din al doilea argument al lui angular.module () este gol, dar nu-l scoateți complet sau veți obține o $ Injector: nomod eroare. Acest lucru se întâmplă deoarece forma unui singur argument angular.module () preia o referință la modulul deja existent, în loc să creeze o nouă.

Furnizorul

Furnizorii sunt una dintre modalitățile de a crea servicii AngularJS. Sintaxa este simplă: primul argument este numele serviciului (nu numele furnizorului!), Iar al doilea este funcția constructorului pentru furnizor:

module.provider ('$ socket', $ socketProvider () ); 

Opțiuni de configurare

Pentru a face biblioteca reutilizabilă, va trebui să permitem modificări în configurația Socket.IO. Mai întâi, să definim două variabile care vor păstra adresa URL a conexiunii și a obiectului de configurare (codul din acest pas merge la $ SocketProvider () funcţie):

 var ioUrl = "; var ioConfig = ; 

Deoarece aceste variabile nu sunt disponibile în afara limbajului $ SocketProvider () (sunt un fel de privat), trebuie să creăm metode (setteri) pentru a le schimba. Putem, desigur, să le facem public asa:

 this.ioUrl = "; this.ioConfig = ; 

Dar:

  1. Va trebui să folosim Function.bind () ulterior pentru a accesa contextul corespunzător pentru acest
  2. Dacă folosim setteri, putem valida pentru a ne asigura că valorile sunt setate - nu vrem să le punem fals dupa cum "timeout timeout" opțiune

O listă completă a opțiunilor pentru Clientul Socket.IO poate fi văzută pe wiki-ul GitHub. Vom crea un setter pentru fiecare dintre ele plus unul pentru adresa URL. Toate metodele par asemănătoare, așa că voi explica codul pentru unul dintre ele și voi pune restul de mai jos.

Să definim prima metodă:

 this.setConnectionUrl = funcția setConnectionUrl (url)  

Ar trebui să verifice tipul de parametru trecut:

 dacă (typeof url == 'string')  

Dacă este cea pe care ne-am așteptat, setați opțiunea:

 ioUrl = url; 

Dacă nu, ar trebui să arunce Eroare de scris:

  altceva aruncați noul TypeError ('url trebuie să fie de tip string'); ; 

Pentru ceilalți, putem crea o funcție de ajutor pentru ao păstra DRY:

 (nume, valoare, tip) if (tip de valoare! = tip) arunca nou TypeError ("'" + nume + "' trebuie să fie de tip" + + + ");  ioConfig [nume] = valoare;  

Pur și simplu aruncă Eroare de scris dacă tipul este greșit, altfel setați valoarea. Iată codul pentru restul opțiunilor:

 this.setResource = funcția setResource (valoare) setOption ('resource', value, 'string'); ; this.setConnectTimeout = funcție setConnectTimeout (valoare) setOption ('timeout timeout', valoare, 'număr'); ; this.setTryMultipleTransports = funcția setTryMultipleTransports (valoare) setOption ('încercați mai multe transporturi', valoare, 'boolean'); ; this.setReconnect = funcția setReconnect (valoare) setOption ('reconectare', valoare, 'boolean'); ; this.setReconnectionDelay = funcția setReconnectionDelay (valoare) setOption ('întârziere de reconectare', valoare, 'număr'); ; this.setReconnectionLimit = set setReconnectionLimit (valoare) setOption ('limit de reconectare', valoare, 'număr'); ; this.setMaxReconnectionAttempts = funcția setMaxReconnectionAttempts (valoare) setOption ('încercări de reconectare max', valoare, 'număr'); ; this.setSyncDisconnectOnUnload = funcția setSyncDisconnectOnUnload (valoare) setOption ('deconectare sincronizare la descărcare', valoare, 'boolean'); ; this.setAutoConnect = funcția setAutoConnect (valoare) setOption ('auto connect', valoare, 'boolean'); ; this.setFlashPolicyPort = funcția setFlashPolicyPort (valoare) setOption ('port de politică flash', valoare, 'număr'); this.setForceNewConnection = funcția setForceNewConnection (valoare) setOption ('forță nouă de conectare', valoare, 'boolean'); ; 

Ai putea să o înlocui cu un singur setOption () , dar se pare mai ușor să tastați numele opțiunii în cazul cămilăi, decât să o transmiteți ca un șir cu spații.

Funcția de fabrică

Această funcție va crea obiectul de serviciu pe care îl vom putea folosi mai târziu (de exemplu în controlere). În primul rând, să sunăm io () pentru conectarea la serverul Socket.IO:

 acest lucru. $ get = funcția $ socketFactory ($ rootScope) var socket = io (ioUrl, ioConfig); 

Rețineți că îi atribuim funcția $ get proprietatea obiectului creat de furnizor - aceasta este importantă deoarece AngularJS folosește acea proprietate pentru ao numi. De asemenea, am pus $ rootScope ca parametru. În acest moment, putem folosi injectarea de dependență a AngularJS pentru a accesa alte servicii. Vom folosi aceasta pentru a propaga modificările la orice modele din callback-urile Socket.IO.

Acum funcția trebuie să returneze un obiect:

 întoarcere  ; ; 

Vom pune toate metodele pentru serviciul în el.

pe() Metodă

Această metodă va atașa un ascultător de evenimente la obiectul socket, astfel încât să putem folosi orice date trimise de pe server:

 on: funcția activă (eveniment, apel invers)  

Vom folosi Socket.IO socket.on () pentru a atașa callback-ul nostru și apelați-l în AngularJS $ Domeniul de aplicare. Aplica $ () metodă. Acest lucru este foarte important, deoarece modelele pot fi modificate numai în interiorul acestuia:

 socket.on (eveniment, funcție ()  

În primul rând, trebuie să copiem argumentele la o variabilă temporară pentru a le putea folosi mai târziu. Argumentele sunt, desigur, tot ceea ce serverul ne-a trimis:

 var args = argumente; 

Apoi, putem apela apelul nostru folosind Function.apply () să-i transmită argumente:

 $ rootScope $ apply (funcția () callback.apply (socket, args);); ); , 

Cand prizăEmițătorul evenimentului solicită funcția de ascultător pe care o folosește $ RootScope. $ Aplică () pentru a apela callback-ul oferit ca al doilea argument pentru .pe() metodă. În acest fel, puteți să vă scrieți ascultătorii evenimentului ca și pentru orice altă aplicație care utilizează Socket.IO, dar puteți modifica modelele lui AngularJS în ele.

off () Metodă

Această metodă va elimina unul sau toți ascultătorii evenimentului pentru un eveniment dat. Acest lucru vă ajută să evitați scurgeri de memorie și comportament neașteptat. Imaginați-vă că utilizați ngRoute și tu atasați puțini ascultători în fiecare controlor. Dacă utilizatorul navighează către altă vizualizare, controlerul dvs. este distrus, dar ascultătorul evenimentului rămâne atașat. După câteva navigări și vom avea o scurgere de memorie.

 oprit: funcția dezactivată (eveniment, apel invers)  

Trebuie doar să verificăm dacă suna inapoi a fost furnizat și sunat socket.removeListener () sau socket.removeAllListeners ():

 dacă (tip callback == 'funcția') socket.removeListener (eveniment, callback);  altceva socket.removeAllListeners (eveniment); , 

emite() Metodă

Aceasta este ultima metodă de care avem nevoie. După cum sugerează și numele, această metodă va trimite date către server:

 emit: funcția emit (eveniment, date, apel invers)  

Deoarece Socket.IO acceptă confirmări, vom verifica dacă suna inapoi a fost oferit. Dacă a fost, vom folosi același model ca în pe() pentru a apela apelul în interiorul lui $ Domeniul de aplicare. Aplica $ ():

 dacă (tip callback == 'funcția') socket.emit (event, data, function () var args = argument; $ rootScope. ); 

Dacă nu există suna inapoi putem să sunăm socket.emit ():

  altfel socket.emit (eveniment, date);  

folosire

Pentru a testa biblioteca, vom crea o formulă simplă care va trimite date către server și va afișa răspunsul. Tot codul JavaScript din această secțiune ar trebui să meargă în > etichetă în a documentului dvs. și a tuturor codurilor HTML .

Crearea modulului

Mai întâi trebuie să creăm un modul pentru aplicația noastră:

var app = angular.module ('exemplu', ['socket.io']); 

Observa asta 'Socket.io' în matrice, în al doilea parametru, spune AngularJS că acest modul depinde de biblioteca noastră Socket.IO.

Funcția Config

Deoarece vom rula dintr-un fișier HTML static, trebuie să specificăm adresa URL de conectare pentru Socket.IO. Putem face acest lucru folosind config () metoda modulului:

app.config (funcția ($ socketProvider) $ socketProvider.setConnectionUrl ('http: // localhost: 8080');); 

După cum puteți vedea, ale noastre $ socketProvider este injectat automat de AngularJS.

Controlerul

Controlorul va fi responsabil pentru toată logica aplicației (aplicația este mică, deci avem nevoie doar de una):

app.controller ('Ctrl', funcția Ctrl ($ scope, $ socket)  

domeniul de aplicare $ este un obiect care deține toate modelele controlerului, este baza legării datelor bi-direcționale a AngularJS. $ soclu este serviciul nostru Socket.IO.

În primul rând, vom crea un ascultător pentru 'ecou' eveniment care va fi transmis de serverul nostru de testare:

 $ socket.on ('echo', funcție (date) $ scope.serverResponse = date;); 

Vom afișa $ scope.serverResponse mai târziu, în HTML, utilizând expresiile AngularJS.

Acum, vor exista și două funcții care vor trimite datele - una utilizând baza emite() metodă și una folosind emite() cu apel de confirmare:

 $ scope.emitBasic = funcția emitBasic () $ socket.emit ('echo', $ scope.dataToSend); $ scope.dataToSend = "; $ scope.emitACK = funcția emitACK () $ socket.emit ('echo-ack', $ scope.dataToSend, funcția (data) $ scope.serverResponseACK = data; $ scope.dataToSend = "; ; ); 

Trebuie să le definim ca metodă domeniul de aplicare $ astfel încât să le putem apela de la ngClick directive în HTML.

HTML-ul

Aici AnglersJS straluceste - putem folosi HTML standard cu cateva atribute personalizate pentru a lega totul impreuna.

Să începem prin definirea modulului principal folosind un ngApp directivă. Plasați acest atribut în eticheta documentului dvs.:

 

Acest lucru spune AngularJS că ar trebui să bootstrap aplicația folosind exemplu modul.

După aceasta, putem crea o formă de bază pentru a trimite date către server:

 
Răspunsul serverului: serverResponse
Răspunsul serverului (ACK): serverResponseACK

Am folosit câteva atribute personalizate și directivele AngularJS:

  • ng-controler - leagă controlerul specificat acestui element, permițându-vă să utilizați valori din domeniul său de aplicare
  • ng model - creează o legătură bidirecțională între element și proprietatea de domeniu specificată (un model), care vă permite să obțineți valori din acest element, precum și să îl modificați în interiorul controlerului
  • ng-clic - atașează a clic un ascultător de evenimente care execută o expresie specificată (citiți mai multe despre expresiile AngularJS)

Plangoanele duble sunt de asemenea expresii AngularJS, ele vor fi evaluate (nu vă faceți griji, nu folosiți JavaScript eval ()) și valoarea lor va fi introdusă acolo.

Dacă ați făcut totul corect, ar trebui să puteți trimite date către server făcând clic pe butoane și să vedeți răspunsul corespunzător

Etichete.


În concluzie

În această primă parte a tutorialului, am creat biblioteca Socket.IO pentru AngularJS, care ne va permite să profităm de WebSockets în aplicațiile noastre cu o singură pagină. În a doua parte, vă voi arăta cum puteți îmbunătăți capacitatea de reacție a aplicațiilor utilizând această combinație.

Cod