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ă.
Î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+.
Î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.
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.
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:
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.
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.
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.
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.
În această secțiune vom crea unghiulare-socket.js
bibliotecă. Tot codul trebuie inserat în acest fișier.
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ă.
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 () );
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:
Function.bind ()
ulterior pentru a accesa contextul corespunzător pentru acest
fals
dupa cum "timeout timeout"
opțiuneO 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.
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);
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 >