Né HTML né HTTP sono stati creati per applicazioni web dinamiche. Fondamentalmente facciamo affidamento sugli hack, oltre agli hack per fornire alle nostre app un'interfaccia utente reattiva. AngularJS rimuove alcune limitazioni dall'HTML, permettendoci di creare e gestire più facilmente il codice dell'interfaccia utente. Socket.IO, d'altra parte ci aiuta a inviare dati dal server non solo quando il client lo richiede, ma anche quando il server ha bisogno di farlo. In questo articolo ti mostrerò come combinare questi due elementi per migliorare la reattività delle tue app a pagina singola.
Nella prima parte di questo tutorial creeremo un servizio AngularJS riutilizzabile per Socket.IO. Per questo motivo riutilizzabile parte, questo sarà un po 'più complicato del semplice utilizzo module.service ()
o module.factory ()
. Queste due funzioni sono solo zucchero sintattico in cima al livello più basso module.provider ()
metodo, che useremo per fornire alcune opzioni di configurazione. Se non hai mai usato AngularJS prima, ti consiglio vivamente di seguire almeno il tutorial ufficiale e alcuni tutorial qui su Tuts+.
Prima di iniziare a scrivere il nostro modulo AngularJS, abbiamo bisogno di un semplice back-end per i test. Se hai già familiarità con Socket.IO puoi semplicemente scorrere verso il basso fino alla fine di questa sezione, copiare la sorgente di back-end e procedere alla successiva, in caso contrario - continua a leggere.
Avremo solo bisogno socket.io
. Puoi installarlo direttamente usando il npm
comando come questo:
npm install socket.io
O creare un package.json
file, inserisci questa riga nel file dipendenze
sezione:
"socket.io": "0.9.x"
Ed esegui il installazione di npm
comando.
Dal momento che non abbiamo bisogno di nessun complicato framework web come Express, possiamo creare il server usando Socket.IO:
var io = require ('socket.io') (8080);
Questo è tutto ciò che serve per configurare il server Socket.IO. Se avvii la tua app, dovresti vedere un output simile nella console:
E dovresti essere in grado di accedere a socket.io.js
file nel browser su http: // localhost: 8080 / socket.io / socket.io.js:
Gestiremo tutte le connessioni in entrata nel connessione
ascoltatore di eventi del io.sockets
oggetto:
io.sockets.on ('connection', function (socket) );
Il presa di corrente
l'attributo passato al callback è il client che si è connesso e possiamo ascoltare gli eventi su di esso.
Ora aggiungeremo un listener di eventi di base nella richiamata sopra. Invierà i dati ricevuti, di nuovo al client usando il socket.emit ()
metodo:
socket.on ('echo', function (data) socket.emit ('echo', data););
eco
è il nome dell'evento personalizzato che useremo in seguito.
Useremo anche i riconoscimenti nella nostra biblioteca. Questa funzione consente di passare una funzione come terzo parametro di socket.emit ()
metodo. Questa funzione può essere richiamata sul server per inviare alcuni dati al client:
socket.on ('echo-ack', funzione (dati, callback) callback (dati););
Ciò consente di rispondere al client senza che sia necessario ascoltare gli eventi (utile se si desidera solo richiedere alcuni dati dal server).
Ora il nostro back-end di test è completo. Il codice dovrebbe apparire come questo (questo è il codice che dovresti copiare se hai omesso questa sezione):
var io = require ('socket.io') (8080); io.sockets.on ('connection', function (socket) socket.on ('echo', function (data) socket.emit ('echo', data);); socket.on ('echo-ack ', funzione (dati, callback) callback (dati);););
Ora dovresti eseguire l'app e lasciarla in esecuzione prima di procedere con il resto del tutorial.
Ovviamente avremo bisogno di un codice HTML per testare la nostra libreria. Dobbiamo includere AngularJS, socket.io.js
dal nostro back-end, il nostro angolari-socket.js
libreria e un controller AngularJS di base per eseguire alcuni test. Il controller sarà inline nel del documento per semplificare il flusso di lavoro:
Questo è tutto ciò di cui abbiamo bisogno per ora, torneremo al tag script vuoto più tardi poiché non abbiamo ancora la libreria.
In questa sezione creeremo il angolari-socket.js
biblioteca. Tutto il codice deve essere inserito in questo file.
Iniziamo con la creazione del modulo per la nostra libreria:
var module = angular.module ('socket.io', []);
Non abbiamo alcuna dipendenza, quindi la matrice nel secondo argomento di angular.module ()
è vuoto, ma non rimuoverlo completamente o si otterrà un $ Iniettore: nomod
errore. Questo accade perché la forma a un argomento di angular.module ()
recupera un riferimento al modulo già esistente, invece di crearne uno nuovo.
I provider sono uno dei modi per creare servizi AngularJS. La sintassi è semplice: il primo argomento è il nome del servizio (non il nome del provider!) E il secondo è la funzione di costruzione per il provider:
module.provider ('$ socket', $ socketProvider () );
Per rendere riutilizzabile la libreria, dovremo consentire le modifiche nella configurazione di Socket.IO. Per prima cosa definiamo due variabili che terranno l'URL per la connessione e l'oggetto di configurazione (il codice in questo passo va al $ SocketProvider ()
funzione):
var ioUrl = "; var ioConfig = ;
Ora dal momento che queste variabili non sono disponibili al di fuori del $ SocketProvider ()
funzione (sono una specie di privato), dobbiamo creare metodi (setter) per cambiarli. Potremmo, naturalmente, solo farli pubblico come questo:
this.ioUrl = "; this.ioConfig = ;
Ma:
Function.bind ()
successivamente per accedere al contesto appropriato per Questo
falso
come il 'collega il timeout'
opzioneUn elenco completo delle opzioni per il client Socket.IO può essere visto sul proprio wiki GitHub. Creeremo un setter per ciascuno di essi più uno per l'URL. Tutti i metodi sono simili, quindi spiegherò il codice per uno di essi e riporterà il resto in basso.
Definiamo il primo metodo:
this.setConnectionUrl = function setConnectionUrl (url)
Dovrebbe controllare il tipo di parametro passato in:
if (typeof url == 'string')
Se è quello che ci aspettavamo, imposta l'opzione:
ioUrl = url;
In caso contrario, dovrebbe gettare TypeError
:
else lanciare un nuovo TypeError ('url deve essere di tipo stringa'); ;
Per il resto, possiamo creare una funzione di supporto per mantenerla ASCIUTTA:
function setOption (name, value, type) if (typeof value! = type) throw new TypeError ("'" + name + "' deve essere di tipo '" + type + "'"); ioConfig [nome] = valore;
Semplicemente getta TypeError
se il tipo è sbagliato, altrimenti imposta il valore. Ecco il codice per il resto delle opzioni:
this.setResource = function setResource (value) setOption ('resource', value, 'string'); ; this.setConnectTimeout = function setConnectTimeout (value) setOption ('connect timeout', valore, 'numero'); ; this.setTryMultipleTransports = function setTryMultipleTransports (value) setOption ('prova più trasporti', valore, 'boolean'); ; this.setReconnect = function setReconnect (value) setOption ('riconnetti', valore, 'booleano'); ; this.setReconnectionDelay = function setReconnectionDelay (valore) setOption ('ritardo di riconnessione', valore, 'numero'); ; this.setReconnectionLimit = function setReconnectionLimit (valore) setOption ('limite di riconnessione', valore, 'numero'); ; this.setMaxReconnectionAttempts = function setMaxReconnectionAttempts (value) setOption ('max riconnessione tentativi', valore, 'numero'); ; this.setSyncDisconnectOnUnload = function setSyncDisconnectOnUnload (value) setOption ('sync disconnect on unload', valore, 'boolean'); ; this.setAutoConnect = function setAutoConnect (value) setOption ('auto connect', valore, 'boolean'); ; this.setFlashPolicyPort = function setFlashPolicyPort (value) setOption ('flash policy port', valore, 'numero'); this.setForceNewConnection = function setForceNewConnection (value) setOption ('forza nuova connessione', valore, 'boolean'); ;
Potresti sostituirlo con un singolo setOption ()
metodo, ma sembra più facile digitare il nome dell'opzione in caso cammello, piuttosto che passarlo come una stringa con spazi.
Questa funzione creerà l'oggetto servizio che potremo utilizzare in seguito (ad esempio nei controller). Per prima cosa, chiamiamo il io ()
funzione per connettersi al server Socket.IO:
this. $ get = function $ socketFactory ($ rootScope) var socket = io (ioUrl, ioConfig);
Si noti che stiamo assegnando la funzione a $ get
proprietà dell'oggetto creato dal provider - questo è importante dal momento che AngularJS usa quella proprietà per chiamarla. Abbiamo anche messo $ rootScope
come il suo parametro. A questo punto, possiamo utilizzare l'iniezione delle dipendenze di AngularJS per accedere ad altri servizi. Lo useremo per propagare le modifiche a qualsiasi modello nei callback Socket.IO.
Ora la funzione deve restituire un oggetto:
ritorno ; ;
Metteremo tutti i metodi per il servizio in esso.
sopra()
MetodoQuesto metodo collegherà un listener di eventi all'oggetto socket, in modo che possiamo utilizzare qualsiasi dato inviato dal server:
on: function on (event, callback)
Useremo Socket.IO's socket.on ()
per allegare la nostra richiamata e chiamarla in AngularJS $ Portata. Applicare $ ()
metodo. Questo è molto importante, perché i modelli possono essere modificati solo all'interno di esso:
socket.on (event, function ()
Per prima cosa, dobbiamo copiare gli argomenti in una variabile temporanea in modo che possiamo usarli in seguito. Gli argomenti sono ovviamente tutto ciò che il server ci ha inviato:
var args = argomenti;
Successivamente, possiamo chiamare la nostra callback usando Function.apply ()
per passare argomenti ad esso:
$ rootScope. $ apply (function () callback.apply (socket, args);); ); ,
quando presa di corrente
L'evento emettitore chiama la funzione listener che usa $ RootScope. Applicare $ ()
chiamare il callback fornito come secondo argomento per il .sopra()
metodo. In questo modo puoi scrivere i tuoi ascoltatori di eventi come faresti per qualsiasi altra app usando Socket.IO, ma puoi modificare i modelli di AngularJS in loro.
off ()
MetodoQuesto metodo rimuoverà uno o tutti i listener di eventi per un determinato evento. Questo ti aiuta a evitare perdite di memoria e comportamenti imprevisti. Immagina che tu stia usando ngRoute
e allega pochi ascoltatori in ogni controller. Se l'utente naviga verso un'altra vista, il controller viene distrutto, ma il listener di eventi rimane collegato. Dopo alcune navigazioni avremo una perdita di memoria.
off: funzione off (evento, callback)
Dobbiamo solo verificare se il richiama
è stato fornito e chiama socket.removeListener ()
o socket.removeAllListeners ()
:
if (typeof callback == 'function') socket.removeListener (event, callback); else socket.removeAllListeners (event); ,
emettere()
MetodoQuesto è l'ultimo metodo di cui abbiamo bisogno. Come suggerisce il nome, questo metodo invierà dati al server:
emit: function emit (evento, dati, callback)
Poiché Socket.IO supporta i riconoscimenti, controlleremo se il file richiama
era fornito. Se lo fosse, useremo lo stesso schema del sopra()
metodo per chiamare il callback all'interno di $ Portata. Applicare $ ()
:
if (typeof callback == 'function') socket.emit (event, data, function () var argomenti = argomenti; $ rootScope. $ apply (function () callback.apply (socket, args);); );
Se non c'è richiama
possiamo solo chiamare socket.emit ()
:
else socket.emit (event, data);
Per testare la libreria, creeremo un semplice modulo che invierà alcuni dati al server e visualizzerà la risposta. Tutto il codice JavaScript in questa sezione dovrebbe andare nel >