Varken HTML eller HTTP skapades för dynamiska webbapplikationer. Vi är i grund och botten beroende av hack, ovanpå hackar för att ge våra appar ett användarvänligt användargränssnitt. AngularJS tar bort några begränsningar från HTML, så att vi enkelt kan skapa och hantera användargränssnittskoden. Socket.IO hjälper oss däremot att skicka data från servern inte bara när kunden begär det, men också när servern behöver. I den här artikeln ska jag visa dig hur du kombinerar dessa två, för att förbättra responsen på dina enkelsidiga appar.
I den första delen av denna handledning skapar vi en återanvändbar AngularJS-tjänst för Socket.IO. På grund av det återanvändbar del kommer det att bli lite svårare än att bara använda module.service ()
eller module.factory ()
. Dessa två funktioner är bara syntaktiskt socker på toppen av den mer låga nivån module.provider ()
metod som vi kommer att använda för att ge några konfigurationsalternativ. Om du aldrig använt AngularJS tidigare rekommenderar jag starkt att du åtminstone följer den officiella handledningen och några av handledningarna här på Tuts+.
Innan vi börjar skriva vår AngularJS-modul behöver vi ett enkelt back-end för testning. Om du redan är bekant med Socket.IO kan du bara rulla ner till slutet av det här avsnittet, kopiera backend-källan och fortsätta till nästa, om inte - läs vidare.
Vi behöver bara socket.io
. Du kan antingen installera den direkt med hjälp av npm
kommando så här:
npm installera socket.io
Eller skapa en package.json
fil, sätt den här raden i beroenden
sektion:
"socket.io": "0.9.x"
Och exekvera npm installera
kommando.
Eftersom vi inte behöver någon komplicerad webbram som Express kan vi skapa servern med Socket.IO:
var io = kräver ('socket.io') (8080);
Det är allt du behöver för att konfigurera Socket.IO-servern. Om du startar din app bör du se liknande resultat i konsolen:
Och du ska kunna komma åt socket.io.js
filen i din webbläsare på http: // localhost: 8080 / socket.io / socket.io.js:
Vi hanterar alla inkommande anslutningar i förbindelse
händelse lyssnare av io.sockets
objekt:
io.sockets.on ('connection', funktion (uttag) );
De uttag
attributet som skickas till återuppringningen är den klient som anslutits och vi kan lyssna på händelser på den.
Nu lägger vi till en bashändelselyttare i återuppringningen ovan. Den kommer att skicka de mottagna dataen, tillbaka till klienten med hjälp av socket.emit ()
metod:
socket.on ('echo', funktion (data) socket.emit ('echo', data););
eko
är det anpassade evenemangsnamnet som vi kommer att använda senare.
Vi kommer också att använda bekräftelser i vårt bibliotek. Med den här funktionen kan du skicka en funktion som den tredje parametern för socket.emit ()
metod. Denna funktion kan kallas på servern för att skicka några data tillbaka till klienten:
socket.on ("echo-ack", funktion (data, återuppringning) callback (data););
Detta gör att du kan svara på klienten utan att behöva lyssna på några händelser (vilket är användbart om du bara vill begära vissa data från servern).
Nu är vårt testback-end färdigt. Koden ska se ut så här (Det här är koden du ska kopiera om du släppte bort det här avsnittet):
var io = kräver ('socket.io') (8080); io.sockets.on ("anslutning", funktion (socket) socket.on ("echo", funktion (data) socket.emit ("echo", data);); socket.on ', funktion (data, återuppringning) callback (data);););
Du ska nu köra appen och lämna den innan du fortsätter med resten av handledningen.
Vi behöver naturligtvis lite HTML för att testa vårt bibliotek. Vi måste inkludera AngularJS, socket.io.js
från vårt back-end, vår vinkel-socket.js
bibliotek och en grundläggande AngularJS-kontroller för att köra några test. Kontrollern kommer att vara inline i av dokumentet för att förenkla arbetsflödet:
Det här är allt vi behöver för nu, vi kommer tillbaka till den tomma skripttaggen senare eftersom vi inte har biblioteket ännu.
I det här avsnittet kommer vi att skapa vinkel-socket.js
bibliotek. All kod måste sättas in i den här filen.
Låt oss börja med att skapa modulen för vår lib:
var modul = angular.module ('socket.io', []);
Vi har inga beroenden, så arrayen i det andra argumentet av angular.module ()
är tom, men ta inte bort det helt eller du får en $ Injektor: nomod
fel. Detta händer på grund av att enargumentformen av angular.module ()
hämtar en referens till den redan existerande modulen istället för att skapa en ny.
Leverantörer är ett sätt att skapa AngularJS-tjänster. Syntaxen är enkel: Det första argumentet är namnet på tjänsten (inte leverantörens namn!) Och den andra är konstruktörfunktionen för leverantören:
module.provider ('$ socket', $ socketProvider () );
För att göra biblioteket återanvändbart måste vi tillåta ändringar i Socket.IOs konfiguration. Låt oss först definiera två variabler som kommer att hålla URL-adressen för anslutningen och konfigurationsobjektet (koden i det här steget går till $ SocketProvider ()
fungera):
var ioUrl = "; var ioConfig = ;
Nu eftersom dessa variabler inte är tillgängliga utanför $ SocketProvider ()
funktion (de är typiska privat), måste vi skapa metoder (setters) för att ändra dem. Vi kunde naturligtvis bara göra dem offentlig så här:
this.ioUrl = "; this.ioConfig = ;
Men:
Function.bind ()
senare för att komma åt det lämpliga sammanhanget för detta
falsk
som den "ansluta timeout"
alternativEn fullständig lista över alternativ för Socket.IOs Client kan ses på deras GitHub wiki. Vi kommer att skapa en setter för var och en av dem plus en för webbadressen. Alla metoder ser likadana ut, så jag kommer att förklara koden för en av dem och lägga resten nedan.
Låt oss definiera den första metoden:
this.setConnectionUrl = funktion setConnectionUrl (url)
Det ska kontrollera vilken typ av parameter som passerat i:
om (typ av url == 'sträng')
Om det är det vi förväntade oss, sätt alternativet:
ioUrl = url;
Om inte, bör det kasta Skrivfel
:
annars släng ny TypeError ('url måste vara av typen sträng'); ;
För resten av dem kan vi skapa en hjälpfunktion för att hålla den torr:
funktion setOption (namn, värde, typ) if (typof value! = typ) kasta ny TypeError ("'" + namn + "" måste vara av typen "" + typ + "" "); ioConfig [namn] = värde;
Det kastar bara Skrivfel
Om typen är fel anger du annars värdet. Här är koden för resten av alternativen:
this.setResource = funktionsuppsättningResource (värde) setOption ('resource', value, 'string'); ; this.setConnectTimeout = funktion setConnectTimeout (värde) setOption ('connect timeout', värde, 'number'); ; this.setTryMultipleTransports = funktion setTryMultipleTransporter (värde) setOption ("försök flera transporter", värde, "boolean"); ; this.setReconnect = function setReconnect (value) setOption ('reconnect', värde, 'boolean'); ; this.setReconnectionDelay = function setReconnectionDelay (value) setOption ('återkopplingsfördröjning', värde, 'nummer'); ; this.setReconnectionLimit = funktion setReconnectionLimit (värde) setOption ('reconnection limit', värde, 'number'); ; this.setMaxReconnectionAttempts = funktionsuppsättningMaxReconnectionAttempts (value) setOption ("max återkopplingsförsök", värde, "nummer"); ; this.setSyncDisconnectOnUnload = function setSyncDisconnectOnUnload (value) setOption ('synkronisera frånkoppling', värde, 'boolean'); ; this.setAutoConnect = funktion setAutoConnect (värde) setOption ("auto connect", värde, "boolean"); ; this.setFlashPolicyPort = funktion setFlashPolicyPort (värde) setOption ('flash policy port', värde, 'number'); this.setForceNewConnection = funktion setForceNewConnection (värde) setOption ('force new connection', värde, 'boolean'); ;
Du kan ersätta den med en enda setoption ()
metod, men det verkar lättare att skriva alternativets namn i kamelfall, snarare än att överföra det som en sträng med mellanslag.
Den här funktionen skapar det serviceobjekt som vi kan använda senare (till exempel i kontroller). Låt oss först ringa io ()
funktion för att ansluta till Socket.IO-servern:
detta. $ get = funktion $ socketFactory ($ rootScope) var socket = io (ioUrl, ioConfig);
Observera att vi tilldelar funktionen till $ get
egenskapen hos objektet skapat av leverantören - det här är viktigt eftersom AngularJS använder den egenskapen för att ringa den. Vi lägger också $ rootScope
som dess parameter. Vid denna tidpunkt kan vi använda AngularJS beroendeinsprutning för att komma åt andra tjänster. Vi kommer att använda den för att sprida ändringar till alla modeller i Socket.IO callbacks.
Nu behöver funktionen returnera ett objekt:
lämna tillbaka ; ;
Vi kommer att lägga alla metoder för tjänsten i den.
på()
MetodDen här metoden kommer att bifoga en händelseloggare till socketobjektet, så vi kan använda alla data som skickas från servern:
på: funktion på (händelse, återuppringning)
Vi kommer att använda Socket.IO: s socket.on ()
att bifoga vår återkallelse och ringa den i AngularJS $ Omfattning. $ Gäller ()
metod. Detta är väldigt viktigt, eftersom modeller bara kan ändras inuti det:
socket.on (händelse, funktion ()
Först måste vi kopiera argumenten till en temporär variabel så att vi kan använda dem senare. Argument är givetvis allt som servern skickade till oss:
var args = argument;
Därefter kan vi ringa vår återuppringning med Function.apply ()
att skicka argument till det:
$ rootScope. $ apply (funktion () callback.apply (socket, args);); ); ,
När uttag
sändningsemitter kallar lyssnarfunktionen som den använder $ RootScope. $ Gäller ()
att ringa återkallningen som den andra argumentet till .på()
metod. På så sätt kan du skriva dina händelselöser som du skulle för någon annan app med Socket.IO, men du kan ändra AngularJS modeller i dem.
av()
MetodDen här metoden tar bort en eller alla händelselyttare för en viss händelse. Detta hjälper dig att undvika minnesläckor och oväntat beteende. Tänk dig att du använder ngRoute
och du bifogar några lyssnare i varje kontroller. Om användaren navigerar till en annan vy förstörs din styrenhet, men händelseläsenaren förblir fäst. Efter några navigeringar har vi en minnesläcka.
av: funktion av (händelse, återuppringning)
Vi behöver bara kolla om ring tillbaka
tillhandahölls och ringde socket.removeListener ()
eller socket.removeAllListeners ()
:
om (typ av återuppringning == 'funktion') socket.removeListener (händelse, återuppringning); annat socket.removeAllListeners (event); ,
avge()
MetodDet här är den sista metoden som vi behöver. Som namnet antyder kommer denna metod att skicka data till servern:
avge: funktion emit (händelse, data, återuppringning)
Eftersom Socket.IO stöder bekräftelser, kommer vi att kontrollera om ring tillbaka
tillhandahölls. Om det var så kommer vi att använda samma mönster som i på()
metod för att ringa uppringningen inuti $ Omfattning. $ Gäller ()
:
om (typ av återuppringning == 'funktion') socket.emit (händelse, data, funktion () var args = arguments; $ rootScope. $ apply (funktion () callback.apply (socket, args);); );
Om det finns nej ring tillbaka
vi kan bara ringa socket.emit ()
:
else socket.emit (händelse, data);
För att testa biblioteket skapar vi en enkel blankett som skickar vissa data till servern och visar svaret. Alla JavaScript-koden i det här avsnittet ska gå i >