var channelMessages = io.connect('http://localhost:3000/messages'), channelMessages.on('message received', function() { /* notify about new message */ }); // ... channelCommands = io.connect('http://localhost:3000/commands'); channelCommands.emit('init'); channelCommands.on('command received', function() { /* process new command */ });
io.connect
call returns a new connection object that has on
and emit
. That's it for such connection objects and I wanted to have an AngularJS service for each for convenient communication with the server. app.factory('socket', function ($rootScope) { var socket = io.connect(); return { on: function (eventName, callback) { socket.on(eventName, function () { var args = arguments; $rootScope.$apply(function () { apply(socket, args); }); }); }, emit: function (eventName, data, callback) { socket.emit(eventName, data, function () { var args = arguments; $rootScope.$apply(function () { if (callback) { callback.apply(socket, args); } }); }) } }; });
on
and emit
, leading to the update of all scopes when a message is received / confirmed to be sent. The connection to the server occurs once when the service is initialized (since AngularJS calls the factory
method once to ensure that the services are singletone).$apply()
. But for this article, this is offtopic.module.service
, which is accepted by the constructor with which the service object will be created on demand. A slightly more flexible way is the module.factory
, which makes it more convenient than directly in the constructor to perform some additional actions before returning the service instance. And the most flexible way is module.provider
. Judging by the name, it can be assumed that it is possible to specify the dependence of client modules on the provider, and write something like socketsProvider.get('foo')
in the client code to get the named connection /foo
. However, module.provider
allows only once to configure the service instance, and the client code should not depend on the provider, but directly on the service itself.on
and emit
of the socket service, adding the first namespace
to them, and keeping a pool of lazy connections inside the service. For each on
or emit
, it would be necessary to check whether a connection already exists with the specified namespace, and if not, create a new one. And for the implementation of objects of named connections, one would have to create lightweight services socketFoo
, socketBar
, etc., which have their own on
and emit
, currying socket.on
and socket.emit
, fixing the namespace parameter with constant values of 'foo' and 'bar'. A working solution, but with a significant drawback - when expanding the set of socket methods, clients of the socketFoo
and socketBar
services socketBar
not be able to call new socket methods without changing the existing code of the socketFoo
and socketBar
. var module = angular.module('myApp.services', []); app.factory('MyService', function() { function MyService(options) { /* */ } MyService.prototype.baz = function() { /* ... */ }; MyService.prototype.qux = function() { /* ... */ }; return MyService; }); // ... module.factory('clientService', function(MyService) { var myService = new MyService({foo: 1, bar: 42}); myService.qux(); // return ... });
camelCase
(meaning that we are dealing with an instance), CamelCase
used to show that the service is actually a designer. Using this approach, the Socket
service was implemented: var services = angular.module('myApp.services', []); services.factory('Socket', ['$rootScope', function($rootScope) { var connections = {}; // , function getConnection(channel) { if (!connections[channel]) { connections[channel] = io.connect('http://localhost:3000/' + channel); } return connections[channel]; } // , namespace- . function Socket(namespace) { this.namespace = namespace; } Socket.prototype.on = function(eventName, callback) { var con = getConnection(this.namespace), self = this; // con.on(eventName, function() { var args = arguments; $rootScope.$apply(function() { callback.apply(con, args); }); }); }; Socket.prototype.emit = function(eventName, data, callback) { var con = getConnection(this.namespace); // . con.emit(eventName, data, function() { var args = arguments; $rootScope.$apply(function() { if (callback) { callback.apply(con, args); } }); }) }; return Socket; }]);
var services = angular.module('myApp.services.channels', []); // . services.factory('channelFoo', function(Socket) { return new Socket('foo'); }); // . services.factory('channelBar', function(Socket) { function ChannelBar() { this.namespace = 'bar'; } ChannelBar.prototype = angular.extend(Socket.prototype, {}); ChannelBar.prototype.start = function() { this.emit('start'); }; ChannelBar.prototype.exit = function() { this.emit('exit'); }; return new ChannelBar(); });
socket.on
and socket.emit
.Socket
service is only a concept. To fully use it, it is necessary to supplement it with the possibility of injecting an io
object, setting the connection string and authorization, as well as the possibility of specifying the scope that should be updated when receiving messages from the server. Code with an example can be found on github .Source: https://habr.com/ru/post/215427/
All Articles