将此websocket工厂更改为angularjs中的socket.io工厂

时间:2014-10-14 06:52:36

标签: angularjs websocket socket.io

导致后端使用nodejs和socket.io,我必须将前端websocket服务更改为socket.io。但是有一些问题。 websocket工厂定义如下:



app.factory("WebSocketDataProvider", function() {

	var WebSocketDataProvider = function(scope) {

		var queuedReqs = [];
		var wssock = null;
		var modelGraphIdIdx = {};


		function getWebSocket() {
			if ("WebSocket" in window) return new WebSocket(WS_URI);
		    else if ("MozWebSocket" in window) return new MozWebSocket(WS_URI);
		    else return null;
		}

		function onOpenWssock() {
			console.log("Connected. Extensions: [" + wssock.extensions + "]");
			console.log("Submitting queued requests:", queuedReqs.length);
			while(queuedReqs.length > 0) wssock.send(queuedReqs.shift());
		}

		function onCloseWssock(e) {
	     	console.log("Disconnected (clean=" + e.wasClean + ", code=" + e.code + ", reason='" + e.reason + "')");
	    	wssock = null;
	   	}
	   	function onMessageWssock(e) {
       		var data = JSON.parse(e.data);
       		if(data.error) {

       			setGlobalAlerts(data);
       			flashAlertsBar();
       		} else if(data.annoEvents) {
       			// annotations //
   				scope.$apply(function(){scope.globalAnno.status = 'dispatching'});
   				if(scope.modelType === 'adhoc') {
   					data._id = scope.graph._id;
   					var ce = new CustomEvent(data._id, {'detail': data });
   					wssock.dispatchEvent(ce);
   				} else {
   					for(var i in modelGraphIdIdx) {
	       				data._id = i;
	       				var ce = new CustomEvent(data._id, {'detail': data });
	       				wssock.dispatchEvent(ce);
       				}
   				}
       			scope.$apply(function(){scope.globalAnno.status = 'dispatched'});
       		} else {
       			// graph data //
	       		var ce = new CustomEvent(data._id, {'detail': data });
	       		wssock.dispatchEvent(ce);
       		}
		}
		function initializeWebSocket() {
			wssock = getWebSocket();
			if(wssock !== null) {
	    		wssock.onopen 		= onOpenWssock;
	   			wssock.onclose 		= onCloseWssock;
	   			wssock.onmessage 	= onMessageWssock;
	   		}
		}
		this.addGraphIdEventListener = function(graphId, funct) {
			wssock.addEventListener(graphId, funct);
			modelGraphIdIdx[graphId] = true;
			if(Object.keys(modelGraphIdIdx).length === scope.modelGraphIds.length) {
				// trigger annotation request as all graph elems are loaded //
				scope.globalAnno.status = 'load';
			}
		}
		this.removeGraphIdEventListener = function(graphId, funct) {
			if(wssock !== null) wssock.removeEventListener(graphId, funct);
		}
		this.requestData = function(query) {
	    	try {
				wssock.send(JSON.stringify(query));
	    	} catch(e) {

	    		if(e.code === 11) {
	    			queuedReqs.push(JSON.stringify(query));
	    		} else {
	    			//reconnect
	    			queuedReqs.push(JSON.stringify(query));
	    			initializeWebSocket();
	    		}
	    	}
	    }
	    this.closeConnection = function() {
	    	wssock.close();
	    }
	    initializeWebSocket();
	}
	return (WebSocketDataProvider);
});




我使用此问题Improve this AngularJS factory to use with socket.io user65873'这样回答:



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;

    var queuedReqs = [];
    var modelGraphIdIdx = {};
    return function(scope) {
        var socket = io(WS_URI);
        var scopedSocket = new ScopedSocket(socket, $rootScope);

        scopedSocket.on('connect', function(){
            while(queuedReqs.length > 0) scopedSocket.emit('queuedReqs', queuedReqs.shift());
        });

        scopedSocket.on('error', function(data){
            setGlobalAlerts(data);
            flashAlertsBar();
        });

        scopedSocket.addGraphIdEventListener = function(graphId, funct) {
            scopedSocket.on(graphId, funct);
            modelGraphIdIdx[graphId] = true;
            if(Object.keys(modelGraphIdIdx).length === scope.modelGraphIds.length) {
                // trigger annotation request as all graph elems are loaded //
                scope.globalAnno.status = 'load';
            }
        }
        scopedSocket.removeGraphIdEventListener = function(graphId, funct) {
            if(scopedSocket !== null) scopedSocket.socket.removeListener(graphId, funct);
        }

        scopedSocket.requestData = function(query) {
            try {
                scopedSocket.emit('query', JSON.stringify(query));
            } catch(e) {

                if(e.code === 11) {
                    queuedReqs.push(JSON.stringify(query));
                } else {
     			   //reconnect
					queuedReqs.push(JSON.stringify(query));
				}
			}
		}

		scopedSocket.closeConnection = function() {
		}

		scope.$on('$destroy', function() {
			scopedSocket.removeAllListeners();
		});
		return scopedSocket;
	};
}]);
&#13;
&#13;
&#13;

但是我在控制台中遇到了这个错误:

Error: [$rootScope:inprog] http://errors.angularjs.org/1.2.9/$rootScope/inprog?p0=%24apply
at Error (native)
at http://localhost:3000/libs/angular/1.2.9/angular.min.js:6:449
at m (http://localhost:3000/libs/angular/1.2.9/angular.min.js:96:353)
at h.$apply (http://localhost:3000/libs/angular/1.2.9/angular.min.js:103:31)
at Socket.processRecievedData (http://localhost:3000/libs/angular-graphing.js:271:12)
at http://localhost:3000/app.js:747:22
at h.$eval (http://localhost:3000/libs/angular/1.2.9/angular.min.js:102:308)
at h.$apply (http://localhost:3000/libs/angular/1.2.9/angular.min.js:103:48)
at Socket.<anonymous> (http://localhost:3000/app.js:746:20)
at Socket.Emitter.emit (http://localhost:3000/libs/socket.io-client/socket.io.js:1194:20)
at Socket.onevent (http://localhost:3000/libs/socket.io-client/socket.io.js:832:10) 

我不知道我的代码中哪里出错了。所以我想得到一些帮助。

1 个答案:

答案 0 :(得分:1)

如果你不想做所有这些艰苦的工作,那么Socket.io已经有了一个Angular界面(btford-angular-socket-io),除非这样做是为了好玩:

您收到的错误是因为$apply调用已完成,而另一个$apply正在进行中。它在这里:

else if (data.annoEvents) {
    // annotations //
    scope.$apply(function () {
        scope.globalAnno.status = 'dispatching'
    });
    if (scope.modelType === 'adhoc') {
        data._id = scope.graph._id;
        var ce = new CustomEvent(data._id, {
            'detail': data
        });
        wssock.dispatchEvent(ce);
    } else {
        for (var i in modelGraphIdIdx) {
            data._id = i;
            var ce = new CustomEvent(data._id, {
                'detail': data
            });
            wssock.dispatchEvent(ce);
        }
    }
    scope.$apply(function () {
        scope.globalAnno.status = 'dispatched'
    });
}

问题是代码的执行速度如此之快,以至于在状态改变之前,是角度范围,以便调度&#39;要求将其更改为“已发送”&#39;启动。只是为了测试您的代码是否有效,您可以在最后调用scope.$digest()而不是调用$apply()

else if (data.annoEvents) {
    // annotations //
    scope.globalAnno.status = 'dispatching'     // it will not be updated in the angular scope
    if (scope.modelType === 'adhoc') {
        data._id = scope.graph._id;
        var ce = new CustomEvent(data._id, {
            'detail': data
        });
        wssock.dispatchEvent(ce);
    } else {
        for (var i in modelGraphIdIdx) {
            data._id = i;
            var ce = new CustomEvent(data._id, {
                'detail': data
            });
            wssock.dispatchEvent(ce);
        }
    }
    scope.globalAnno.status = 'dispatched'
    scope.$digest();
}

$digest调用的问题是status='dispatching'不会在角度范围内更新,因此您无法在UI或其他位置看到它。

现在,您可能想重新考虑架构。我建议您使用Angular事件。如果你考虑一下,你已经在处理来自socket.io/websocket的事件,那么为什么不让它们与angular一起工作呢。 (angular-socket-io有一个类似的方法,所以你可以检查它的例子)

不是将状态存储在变量scope.globalAnno.status = 'dispatching'上,而是从根作用域中发出它并在需要的地方使用它:$rootScope.$emit('socket:dispatching')