이 각도 개선소켓과 함께 사용하는 JS 공장.이오
AngularJS에서 socket.io을 사용하고 싶습니다.다음 공장을 찾았습니다.
app.factory('socket', function ($rootScope) {
var socket = io.connect();
return {
on: function (eventName, callback) {
socket.on(eventName, function () {
var args = arguments;
$rootScope.$apply(function () {
callback.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);
}
});
})
}
};
컨트롤러에서는 다음과 같이 사용됩니다.
function MyCtrl($scope, socket) {
socket.on('message', function(data) {
...
});
};
문제는 컨트롤러가 방문할 때마다 다른 청취자가 추가되기 때문에 메시지가 수신되면 여러 번 처리된다는 것입니다.
socket.io과 AngularJS를 통합하는 더 나은 전략은 무엇일까요?
EDIT: 공장에서 아무것도 반환하지 않고 청취한 후 $rootScope를 사용할 수 있습니다.$190과 $190입니다.컨트롤러에 $1이 있지만, 좋은 솔루션이 아닌 것 같습니다.
EDIT2: 공장 출하 시 추가
init: function() {
socket.removeAllListeners();
}
socket.io 를 사용하는 각 컨트롤러의 선두에서 호출합니다.
여전히 최선의 해결책은 아닌 것 같아요
컨트롤러가 파괴될 때마다 소켓청취기를 분리합니다. 묶어야 요.$destroy
다음과 같이 합니다.
function MyCtrl($scope, socket) {
socket.on('message', function(data) {
...
});
$scope.$on('$destroy', function (event) {
socket.removeAllListeners();
// or something like
// socket.removeListener(this);
});
};
자세한 내용은 angularjs 설명서를 참조하십시오.
하고 Scope를 으로 이 할 수 .$destroy
브로드캐스트되는 경우 해당 스코프의 컨텍스트에서 추가된 청취자만 소켓에서 삭제합니다.주의: 다음 내용은 테스트되지 않았습니다.
// A ScopedSocket is an object that provides `on` and `emit` methods,
// but keeps track of all listeners it registers on the socket.
// A call to `removeAllListeners` will remove all listeners on the
// socket that were created via this particular instance of ScopedSocket.
var ScopedSocket = function(socket, $rootScope) {
this.socket = socket;
this.$rootScope = $rootScope;
this.listeners = [];
};
ScopedSocket.prototype.removeAllListeners = function() {
// Remove each of the stored listeners
for(var i = 0; i < this.listeners.length; i++) {
var details = this.listeners[i];
this.socket.removeListener(details.event, details.fn);
};
};
ScopedSocket.prototype.on = function(event, callback) {
var socket = this.socket;
var $rootScope = this.$rootScope;
var wrappedCallback = function() {
var args = arguments;
$rootScope.$apply(function() {
callback.apply(socket, args);
});
};
// Store the event name and callback so we can remove it later
this.listeners.push({event: event, fn: wrappedCallback});
socket.on(event, wrappedCallback);
};
ScopedSocket.prototype.emit = function(event, data, callback) {
var socket = this.socket;
var $rootScope = this.$rootScope;
socket.emit(event, data, function() {
var args = arguments;
$rootScope.$apply(function() {
if (callback) {
callback.apply(socket, args);
}
});
});
};
app.factory('Socket', function($rootScope) {
var socket = io.connect();
// When injected into controllers, etc., Socket is a function
// that takes a Scope and returns a ScopedSocket wrapping the
// global Socket.IO `socket` object. When the scope is destroyed,
// it will call `removeAllListeners` on that ScopedSocket.
return function(scope) {
var scopedSocket = new ScopedSocket(socket, $rootScope);
scope.$on('$destroy', function() {
scopedSocket.removeAllListeners();
});
return scopedSocket;
};
});
function MyController($scope, Socket) {
var socket = Socket($scope);
socket.on('message', function(data) {
...
});
};
수락된 답변에 코멘트를 추가하고 싶지만 할 수 없습니다.그래서 답장을 쓸게요.저도 같은 문제가 있었습니다만, 제가 찾은 가장 쉽고 간단한 해답은 여기 michaeljoser가 제공한 다른 게시물에서 찾을 수 있습니다.
편의를 위해 아래를 복사해 두겠습니다.
remove All Listeners를 공장에 추가하고(아래 참조), 각 컨트롤러에 다음 코드를 설정해야 합니다.
$scope.$on('$destroy', function (event) {
socket.removeAllListeners();
});
출고 시 소켓 업데이트:
var socket = io.connect('url');
return {
on: function (eventName, callback) {
socket.on(eventName, function () {
var args = arguments;
$rootScope.$apply(function () {
callback.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);
}
});
})
},
removeAllListeners: function (eventName, callback) {
socket.removeAllListeners(eventName, function() {
var args = arguments;
$rootScope.$apply(function () {
callback.apply(socket, args);
});
});
}
};
});
덕분에 목숨이 건졌어요. 다른 사람에게 도움이 됐으면 좋겠어요!
다음과 같이 서비스 또는 공장에서 기능을 생성하십시오.
unSubscribe: function(listener) {
socket.removeAllListeners(listener);
}
그 후 아래와 같은 "$seconds" 이벤트로 컨트롤러를 호출합니다.
$scope.$on('$destroy', function() {
yourServiceName.unSubscribe('eventName');
});
그것으로 해결되었다
저는 이 글을 읽기 전에 비슷한 문제를 풀었어요.난 군대에서 다 했어
.controller('AlertCtrl', ["$scope", "$rootScope", "Socket", function($scope, $rootScope, Socket) {
$scope.Socket = Socket;
}])
// this is where the alerts are received and passed to the controller then to the view
.factory('Socket', ["$rootScope", function($rootScope) {
var Socket = {
alerts: [],
url: location.protocol+'//'+location.hostname+(location.port ? ':'+location.port: ''),
// io is coming from socket.io.js which is coming from Node.js
socket: io.connect(this.url)
};
// set up the listener once
// having this in the controller was creating a
// new listener every time the contoller ran/view loaded
// has to run after Socket is created since it refers to itself
(function() {
Socket.socket.on('get msg', function(data) {
if (data.alert) {
Socket.alerts.push(data.alert);
$rootScope.$digest();
}
});
}());
return Socket;
}])
다른 방법을 시도했지만 예상대로 되지 않았다.★★★★★★★를 사용하고 있습니다.socket
되어 있습니다.MainController
a. a. a.GameController
. 했을 때, 나는 단지 '보다'가 생성한 GameController
를 남겨주세요.MainController
running을 할 수 없기 때문에removeAllListeners
기능.대신, 내 안에 중복이 생기지 않도록 하는 더 좋은 방법을 찾았습니다.socket
공장 출하 시:
app.factory('socket', function ($rootScope) {
var socket = io.connect();
function on(eventName, callback) {
socket.on(eventName, function () {
var args = arguments;
$rootScope.$apply(function () {
callback.apply(socket, args);
});
});
// Remove duplicate listeners
socket.removeListener(eventName, callback);
}
function emit(eventName, data, callback) {
socket.emit(eventName, data, function () {
var args = arguments;
$rootScope.$apply(function () {
if (callback) {
callback.apply(socket, args);
}
});
});
// Remove duplicate listeners
socket.removeListener(eventName, callback);
}
return {
on: on,
emit: emit
};
}
app.factory를 실행하는 대신 다음과 같은 서비스(싱글톤)를 만듭니다.
var service = angular.module('socketService', []);
service.factory('$socket', function() {
// Your factory logic
});
그런 다음 $rootScope와 같이 단순히 앱에 서비스를 주입하고 컨트롤러에서 사용할 수 있습니다.
다음은 이 설정을 수행하는 방법에 대한 자세한 예입니다.
// App module
var app = angular.module('app', ['app.services']);
// services
var services = angular.module('app.services', []);
// Socket service
services.factory('$socket', ['$rootScope', function(rootScope) {
// Factory logic here
}]);
// Controller
app.controller('someController', ['$scope', '$socket', function(scope, socket) {
// Controller logic here
}]);
위의 Brandon의 답변에 대해 자세히 설명하자면, 저는 1)와 같은 각진 태그를 추가로 제거하는 서비스를 만들었습니다.$$hashKey는 요소에 남습니다.그리고 2) 소켓소프('..').on(')과 같은 이름붙인 소켓을 사용할 수 있습니다.'
(function (window, app, undefined) {
'use strict';
var ScopedSocket = function (socket, $rootScope) {
this.socket = socket;
this.$rootScope = $rootScope;
this.listeners = [];
this.childSockets = [];
};
ScopedSocket.prototype.removeAllListeners = function () {
var i;
for (i = 0; i < this.listeners.length; i++) {
var details = this.listeners[i];
this.socket.removeListener(details.event, details.fn);
}
for (i = 0; i < this.childSockets.length; i++) {
this.childSockets[i].removeAllListeners();
}
};
ScopedSocket.prototype.on = function (event, callback) {
var socket = this.socket;
var $rootScope = this.$rootScope;
this.listeners.push({event: event, fn: callback});
socket.on(event, function () {
var args = arguments;
$rootScope.$apply(function () {
callback.apply(socket, args);
});
});
};
ScopedSocket.prototype.emit = function (event, data, callback) {
var socket = this.socket;
var $rootScope = this.$rootScope;
socket.emit(event, angular.fromJson(angular.toJson(data)), function () {
var args = arguments;
$rootScope.$apply(function () {
if (callback) {
callback.apply(socket, args);
}
});
});
};
ScopedSocket.prototype.of = function (channel) {
var childSocket = new ScopedSocket(this.socket.of(channel), this.$rootScope);
this.childSockets.push(childSocket);
return childSocket;
};
app.factory('Socket', ['$rootScope', function ($rootScope) {
var socket = $rootScope.socket;
return function(scope) {
var scopedSocket = new ScopedSocket(socket, $rootScope);
scope.$on('$destroy', function() {
scopedSocket.removeAllListeners();
});
return scopedSocket;
};
}]);
})(window, window.app);
저는 아래 코드 같은 것을 사용하고 있습니다.sockets Service는 한 번만 인스턴스화되며 Angular는 GC를 $on으로 처리합니다.
$broadcast/$on이 마음에 들지 않는 경우 Angular를 위한 메시지 버스 구현이 약간 더 있습니다.
app.service('socketsService', ['$rootScope', function ($rootScope) {
var socket = window.io.connect();
socket.on('info', function(data) {
$rootScope.$broadcast("info_received", data);
});
socket.emit('ready', "Hello");
}]);
app.controller("infoController",['$scope',
function ($scope) {
$scope.$root.$on("info_received", function(e,data){
console.log(data);
});
//...
}]);
app.run(
['socketsService',
function (socketsService) {
//...
}]);
나는 청취자가 이미 존재하는지 확인함으로써 이 문제를 해결했다.여러 컨트롤러가 동시에 로딩되어 있는 경우(모두 소켓을 사용하는 다른 페이지모듈을 생각할 수 있습니다).IO)에서 등록된 모든 청취자를 삭제합니다.$destroy
파괴된 컨트롤러와 아직 로딩되어 있는 모든 컨트롤러의 기능이 파손됩니다.
app.factory("SocketIoFactory", function ($rootScope) {
var socket = null;
var nodePath = "http://localhost:12345/";
function listenerExists(eventName) {
return socket.hasOwnProperty("$events") && socket.$events.hasOwnProperty(eventName);
}
return {
connect: function () {
socket = io.connect(nodePath);
},
connected: function () {
return socket != null;
},
on: function (eventName, callback) {
if (!listenerExists(eventName)) {
socket.on(eventName, function () {
var args = arguments;
$rootScope.$apply(function () {
callback.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: function (eventName, callback) {
//avoid duplicated listeners
if (listeners[eventName] != undefined) return;
socket.on(eventName, function () {
var args = arguments;
$rootScope.$apply(function () {
callback.apply(socket, args);
});
listeners[eventName] = true;
});
},
브라우저를 새로 고친 후에도 동일한 이벤트가 중복되는 문제가 발생했습니다.'공장'을 사용하다가 '서비스'로 전환했습니다.socket.io 래퍼입니다.
myApp.service('mysocketio',['$rootScope', function($rootScope)
{
var socket = io.connect();
return {
on: function(eventName, callback )
{
socket.on(eventName, function()
{
var args=arguments;
$rootScope.$apply(function()
{
callback.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);
}
});
});
}
}
}]);
컨트롤러 내에서 이 서비스를 사용하여 이벤트를 듣습니다.
myApp.controller('myController', ['mysocketio', function(mysocketio)
{
mysocketio.on( 'myevent', function(msg)
{
console.log('received event: ' + msg );
}
}]);
공장에서 서비스 사용으로 전환한 후 브라우저 새로 고침 후 중복이 발생하지 않습니다.
Angular App에서 위의 코드를 사용하여 시도해보니 이벤트가 중복되어 있습니다.SocketIoFactory를 사용한@pootzko의 같은 예
추가했습니다.unSubscribe(even_name)
내부$destroy
socketEventListner를 삭제 또는 클리어합니다.
var app = angular.module("app", []);
..
..
..
//Create a SocketIoFactory
app.service('SocketIoFactory', function($rootScope){
console.log("SocketIoFactory....");
//Creating connection with server
var protocol = 'ws:',//window.location.protocol,
host = window.location.host,
port = 80,
socket = null;
var nodePath = protocol+'//'+host+':'+port+'/';
function listenerExists(eventName) {
return socket.hasOwnProperty("$events") && socket.$events.hasOwnProperty(eventName);
}
return {
connect: function () {
socket = io.connect(nodePath);
console.log('SOCKET CONNECTION ... ',nodePath);
},
connected: function () {
return socket != null;
},
on: function (eventName, callback) {
if (!listenerExists(eventName)) {
socket.on(eventName, function () {
var args = arguments;
$rootScope.$apply(function () {
callback.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);
}
});
})
},
unSubscribe: function(listener) {
socket.removeAllListeners(listener);
}
};
});
..
..
..
//Use in a controller
app.controller("homeControl", ['$scope', 'SocketIoFactory', function ($scope, SocketIoFactory) {
//Bind the events
SocketIoFactory.on('<event_name>', function (data) {
});
//On destroy remove the eventListner on socketConnection
$scope.$on('$destroy', function (event) {
console.log('[homeControl] destroy...');
SocketIoFactory.unSubscribe('<event_name>');
});
}]);
언급URL : https://stackoverflow.com/questions/14389049/improve-this-angularjs-factory-to-use-with-socket-io
'programing' 카테고리의 다른 글
jQuery를 사용하여 JSON 개체에 키가 있는지 확인합니다. (0) | 2023.04.02 |
---|---|
_post_thumbnail 폭을 100%로 설정 (0) | 2023.04.02 |
모바일 버전에 대해 다른 정적 홈페이지를 설정하는 방법(WordPress) (0) | 2023.04.02 |
WordPress에서 프로그래밍 방식으로 섬네일이 있는 게시물 추가 (0) | 2023.04.02 |
Intellissense for Jest는 VS 코드로 동작하지 않습니다. (0) | 2023.04.02 |