Er zijn geen HTML of HTTP gemaakt voor dynamische webtoepassingen. We baseren ons in feite op hacks, bovenop hacks om onze apps een responsieve gebruikersinterface te geven. AngularJS verwijdert enkele beperkingen van HTML, waardoor we gebruikersinterfacecode eenvoudiger kunnen maken en beheren. Socket.IO aan de andere kant helpt ons om gegevens van de server te verzenden, niet alleen wanneer de client daarom vraagt, maar ook wanneer de server dit moet doen. In dit artikel laat ik zien hoe je deze twee kunt combineren om de responsiviteit van je apps met één pagina te verbeteren.
In het eerste deel van deze tutorial zullen we een herbruikbare AngularJS-service voor Socket.IO maken. Daarom herbruikbare een deel, dit zal een beetje lastiger zijn dan alleen maar gebruiken module.service ()
of module.factory ()
. Deze twee functies zijn slechts syntactische suiker bovenop het meer lage niveau module.provider ()
methode, die we zullen gebruiken om enkele configuratie-opties te bieden. Als u AngularJS nog nooit eerder hebt gebruikt, raad ik u ten zeerste aan om ten minste de officiële zelfstudie en enkele van de handleidingen hier op Tuts te volgen+.
Voordat we beginnen met het schrijven van onze AngularJS-module, hebben we een eenvoudige back-end nodig om te testen. Als u al bekend bent met Socket.IO, kunt u gewoon naar het einde van dit gedeelte scrollen, de back-endbron kopiëren en doorgaan naar de volgende, zo niet - lees verder.
We zullen alleen nodig hebben socket.io
. U kunt het rechtstreeks installeren met behulp van de NPM
commando als volgt:
npm install socket.io
Of maak een package.json
bestand, zet deze regel in de afhankelijkheden
sectie:
"socket.io": "0.9.x"
En voer het uit npm installeren
commando.
Omdat we geen ingewikkeld webraamwerk zoals Express nodig hebben, kunnen we de server maken met Socket.IO:
var io = require ('socket.io') (8080);
Dat is alles wat u nodig hebt om de Socket.IO-server in te stellen. Als u uw app start, ziet u vergelijkbare uitvoer in de console:
En je zou toegang moeten hebben tot de socket.io.js
bestand in uw browser op http: // localhost: 8080 / socket.io / socket.io.js:
We zullen alle inkomende verbindingen in de verbinding
gebeurtenis luisteraar van de io.sockets
voorwerp:
io.sockets.on ('verbinding', functie (socket) );
De stopcontact
attribuut doorgegeven aan de callback is de client die is verbonden en we kunnen naar gebeurtenissen erop luisteren.
Nu voegen we een basisgebeurtenislistener toe in de bovenstaande callback. Het stuurt de ontvangen gegevens terug naar de client met behulp van de socket.emit ()
methode:
socket.on ('echo', functie (data) socket.emit ('echo', data););
echo
is de aangepaste evenementnaam die we later zullen gebruiken.
We zullen ook bevestigingen gebruiken in onze bibliotheek. Met deze functie kunt u een functie doorgeven als de derde parameter van de socket.emit ()
methode. Deze functie kan op de server worden aangeroepen om bepaalde gegevens terug naar de client te verzenden:
socket.on ('echo-ack', functie (data, callback) callback (data););
Hiermee kunt u reageren op de client zonder dat deze naar gebeurtenissen hoeft te luisteren (wat handig is als u slechts enkele gegevens van de server wilt opvragen).
Nu is onze testback-end voltooid. De code zou er zo uit moeten zien (dit is de code die u moet kopiëren als u deze sectie overslaat):
var io = require ('socket.io') (8080); io.sockets.on ('verbinding', functie (socket) socket.on ('echo', functie (data) socket.emit ('echo', data);); socket.on ('echo-ack ', functie (data, callback) callback (data);););
Start nu de app en laat hem draaien voordat je verder gaat met de rest van de tutorial.
We hebben natuurlijk wat HTML nodig om onze bibliotheek te testen. We moeten AngularJS opnemen, socket.io.js
van onze back-end, onze hoekige socket.js
bibliotheek en een eenvoudige AngularJS-controller om een aantal tests uit te voeren. De controller is inline in de van het document om de workflow te vereenvoudigen:
Dit is alles wat we nu nodig hebben, we zullen later teruggaan naar de lege scripttag omdat we de bibliotheek nog niet hebben.
In deze sectie maken we de hoekige socket.js
bibliotheek. Alle code moet in dit bestand worden geplaatst.
Laten we beginnen met het maken van de module voor onze lib:
var module = angular.module ('socket.io', []);
We hebben geen afhankelijkheden, dus de array in het tweede argument van angular.module ()
is leeg, maar verwijder het niet volledig, anders krijg je een $ Injector: nomod
fout. Dit gebeurt omdat de vorm met één argument angular.module ()
haalt een verwijzing naar de reeds bestaande module op, in plaats van een nieuwe te maken.
Providers zijn een van de manieren om AngularJS-services te maken. De syntaxis is eenvoudig: het eerste argument is de naam van de service (niet de naam van de provider!) En de tweede is de constructorfunctie voor de provider:
module.provider ('$ socket', $ socketProvider () );
Om de bibliotheek herbruikbaar te maken, moeten we wijzigingen in de configuratie van Socket.IO toestaan. Laten we eerst twee variabelen definiëren die de URL voor de verbinding en het configuratieobject bevatten (code in deze stap gaat naar de $ SocketProvider ()
functie):
var ioUrl = "; var ioConfig = ;
Nu aangezien deze variabelen niet beschikbaar zijn buiten de $ SocketProvider ()
functie (ze zijn een soort van privaat), we moeten methoden (setters) maken om ze te veranderen. We kunnen ze natuurlijk gewoon maken openbaar zoals dit:
this.ioUrl = "; this.ioConfig = ;
Maar:
Function.bind ()
later om toegang te krijgen tot de juiste context voor deze
vals
als de 'sluit time-out'
keuzeEen volledige lijst met opties voor de Client van Socket.IO is te zien op hun GitHub-wiki. We zullen een setter maken voor elk van hen plus een voor de URL. Alle methoden lijken op elkaar, dus ik zal de code voor een van de methoden uitleggen en de rest hieronder zetten.
Laten we de eerste methode definiëren:
this.setConnectionUrl = function setConnectionUrl (url)
Er moet worden gecontroleerd welk type parameter is doorgegeven:
if (typeof url == 'string')
Als dit degene is die we verwachtten, stel dan de optie in:
ioUrl = url;
Zo niet, dan zou het moeten gooien Typefout
:
else gooi nieuwe TypeError ('url moet van het type string zijn'); ;
Voor de rest kunnen we een helperfunctie maken om het droog te houden:
functie setOption (naam, waarde, type) if (type van waarde! = type) gooi nieuwe TypeError ("'" + naam + "' moet van het type '" + type + "'" zijn); ioConfig [naam] = waarde;
Het gooit gewoon Typefout
als het type verkeerd is, zet anders de waarde. Hier is de code voor de rest van de opties:
this.setResource = function setResource (value) setOption ('resource', value, 'string'); ; this.setConnectTimeout = functie setConnectTimeout (waarde) setOption ('connect timeout', value, 'number'); ; this.setTryMultipleTransports = functiesetTryMultipleTransports (waarde) setOption ('try multiple transports', value, 'boolean'); ; this.setReconnect = functie setReconnect (waarde) setOption ('reconnect', value, 'boolean'); ; this.setReconnectionDelay = function setReconnectionDelay (value) setOption ('reconnection delay', value, 'number'); ; this.setReconnectionLimit = functie setReconnectionLimit (waarde) setOption ('reconnection limit', value, 'number'); ; this.setMaxReconnectionAttempts = function setMaxReconnectionAttempts (value) setOption ('max heraansluitpogingen', waarde, 'nummer'); ; this.setSyncDisconnectOnUnload = functie setSyncDisconnectOnUnload (waarde) setOption ('sync disconnect on unload', value, 'boolean'); ; this.setAutoConnect = function setAutoConnect (value) setOption ('auto connect', value, 'boolean'); ; this.setFlashPolicyPort = functie setFlashPolicyPort (waarde) setOption ('flash policy port', value, 'number'); this.setForceNewConnection = function setForceNewConnection (value) setOption ('force new connection', value, 'boolean'); ;
Je zou het kunnen vervangen door een single SetOption ()
methode, maar het lijkt gemakkelijker om de naam van de optie in kameelgeval te typen, in plaats van het door te geven als een reeks met spaties.
Met deze functie wordt het service-object gemaakt dat we later kunnen gebruiken (bijvoorbeeld in controllers). Laten we eerst de io()
functie om verbinding te maken met de Socket.IO-server:
this. $ get = function $ socketFactory ($ rootScope) var socket = io (ioUrl, ioConfig);
Merk op dat we de functie toewijzen aan de $ get
eigenschap van het object gemaakt door de provider - dit is belangrijk omdat AngularJS die eigenschap gebruikt om het te noemen. We zetten ook $ rootScope
als zijn parameter. Op dit punt kunnen we de afhankelijkheidsinjectie van AngularJS gebruiken voor toegang tot andere services. We zullen het gebruiken om wijzigingen door te geven aan alle modellen in Socket.IO-callbacks.
Nu moet de functie een object retourneren:
terug ; ;
We zullen alle methoden voor de service erin stoppen.
op()
MethodeDeze methode koppelt een gebeurtenislistener aan het socketobject, zodat we alle gegevens kunnen gebruiken die vanaf de server zijn verzonden:
on: function on (event, callback)
We zullen Socket.IO's gebruiken socket.on ()
om onze callback toe te voegen en deze in AngularJS's te bellen $ Scope. $ Van toepassing zijn ()
methode. Dit is erg belangrijk, omdat modellen alleen binnenin kunnen worden gewijzigd:
socket.on (event, function ()
Eerst moeten we de argumenten naar een tijdelijke variabele kopiëren, zodat we ze later kunnen gebruiken. Argumenten zijn natuurlijk alles dat de server naar ons heeft gestuurd:
var args = argumenten;
Vervolgens kunnen we onze callback bellen met Function.apply ()
om argumenten aan te geven:
$ rootScope. $ apply (function () callback.apply (socket, args);); ); ,
Wanneer stopcontact
's gebeurtenis-emitter roept de listener-functie aan die het gebruikt $ RootScope. $ Van toepassing zijn ()
om de callback genoemd als het tweede argument voor de .op()
methode. Op deze manier kun je jouw evenement luisteraars zoals je zou voor elke andere app schrijven met behulp van Socket.IO, maar je kunt de AngularJS modellen in hen aanpassen.
uit()
MethodeDeze methode verwijdert een of alle gebeurtenislisteners voor een bepaalde gebeurtenis. Dit helpt u om geheugenlekken en onverwacht gedrag te voorkomen. Stel je voor dat je gebruikt ngRoute
en je bevestigt weinig luisteraars in elke controller. Als de gebruiker naar een andere weergave navigeert, wordt uw controller vernietigd, maar blijft de gebeurtenislistener gehecht. Na enkele navigatiebeurten hebben we een geheugenlek.
uit: functie uit (gebeurtenis, callback)
We hoeven alleen maar te controleren of het Bel terug
werd verstrekt en bel socket.removeListener ()
of socket.removeAllListeners ()
:
if (type van callback == 'function') socket.removeListener (event, callback); else socket.removeAllListeners (event); ,
zenden ()
MethodeDit is de laatste methode die we nodig hebben. Zoals de naam al doet vermoeden, verzendt deze methode gegevens naar de server:
uitstoten: functie-uitzending (gebeurtenis, data, callback)
Aangezien Socket.IO bevestigingen ondersteunt, zullen we controleren of de Bel terug
werd verstrekt. Als dat zo was, gebruiken we hetzelfde patroon als in de op()
methode om callback binnen van te roepen $ Scope. $ Van toepassing zijn ()
:
if (typeof callback == 'function') socket.emit (event, data, function () var args = arguments; $ rootScope. $ apply (function () callback.apply (socket, args);); );
Als er geen Bel terug
we kunnen gewoon bellen socket.emit ()
:
else socket.emit (event, data);
Om de bibliotheek te testen, zullen we een eenvoudig formulier maken dat enkele gegevens naar de server zal sturen en het antwoord zal weergeven. Alle JavaScript-code in dit gedeelte moet in de >