websocket并不总是在angularjs应用程序中触发onopen函数

Posted

技术标签:

【中文标题】websocket并不总是在angularjs应用程序中触发onopen函数【英文标题】:websocket not always firing onopen function in angularjs app 【发布时间】:2015-04-09 16:36:16 【问题描述】:

我有一个应用程序从外部设备读取一些值。我使用 angularjs 作为我的 javascript 框架。我正在使用 angular-ui 进行路由。

我正在使用 resolve 将 Web 套接字传递给控制器​​,因为它可以在多个屏幕中使用

.state('dashboard.count', 
    parent: 'dashboard',
    url: "/lane/:laneID",
    templateUrl: '/app/count/count.html',
    controller: 'CountCtrl as vm',
    resolve: 
        websocket: ['webSocketFactory', function (webSocketFactory) 
            return webSocketFactory.websocket;
        ]
    
);

websocket 由工厂检索:

function webSocketFactory($log, wsUri) 
    var factory = 
        sendMessage: sendMessage,
        websocket: new WebSocket('myurl')
    

    return factory;
    

在我的控制器中,我有一个简单的 websocket API 调用

websocket.onopen = function () 
    $log.debug('open');
    webSocketFactory.sendMessage('send my message through the factory');
    vm.connecting = false;

可能有 70% 的时间可以正常工作 vm.connecting 设置为 false,我可以使用 web-socket。然而,这是不可预测的。

我对这个SO Question 接受的答案并不满意,投票较高的似乎是我遵循的模式。有没有人有任何建议如何使这更可预测?

【问题讨论】:

【参考方案1】:

我怀疑它不可靠,因为onopen 回调会在您的控制器实例准备好之前发生。如果我是对的,下面的代码应该可以工作,并且还允许您排队等待 websocket 连接后立即发送的消息。

尝试在创建new WebSocket() 后立即添加onopen 函数,并让服务处理套接字而不是控制器的所有内部工作。

function webSocketService($rootScope, $log, $q, wsUri) 

    var websocketConnectedDeferred, isConnected, websocket;

    var createNewWebSocket = function(url)
        websocketConnectedDeferred = $q.defer();
        isConnected = false;

        websocket = new WebSocket(url)
        websocket.onopen = onWebSocketOpen;
        websocket.onmessage = onWebSocketMessage;

        return websocket;
    ;

    var onWebSocketOpen = function()
        $log.debug('open');
        isConnected = true;
        websocketConnectedDeferred.resolve();
    ;

    var onWebSocketMessage = function(incomingMessage)
        $rootScope.$broadcast('websocketMessageReceived', incomingMessage);
    ;

    var sendMessage = function(message)
        websocketConnectedDeferred.promise.then(function()
            websocket.doTheThing(message);
        );
    ;

    var iswebsocketConnectedDeferred = function()
        return isConnected;
    ;

    var service = 
        sendMessage: sendMessage,
        websocket: createNewWebSocket('myUrl'),
        iswebsocketConnectedDeferred: iswebsocketConnectedDeferred
    ;

    return service;

控制器:

$scope.$on('websocketMessageReceived', function(event, incomingMessage)
    // Do something with 'incomingMessage'
);

webSocketService.sendMessage('send my message through the factory');

【讨论】:

认为有必要在控制器中放入任何东西解析吗? 对于要发送的消息,不,它会在promise解析时由服务发送。如果您希望控制器在连接成功后执行某些操作(向用户显示一些“已连接”消息或其他任何内容),则添加一个方法以返回 websocketConnectedPromise.promise 并对其做出响应。 webSocketFactory.connected().then(function() $scope.connectedStatus = 'Connected!!!' ); 如果工厂持有插座,您如何将.onmesssage放入控制器中? 哦,我忘了提一件事。如果您使 webSocketFactory 成为服务而不是工厂,或者像您在示例中所做的那样解析它,那么您将在每个控制器中获得相同的实例,并且您不需要任何状态解析代码。 myModule.service('WebSocetService, function($log, $q, wsUri) ... ); 您仍然可以将 onmessage 函数分配给 websocket,如下所示:webSocketFactory.websocket.onmessages = function(); 我仍然更喜欢将所有逻辑从控制器中抽象出来,所以我会使用一个事件从服务。我会用一个例子来更新答案。

以上是关于websocket并不总是在angularjs应用程序中触发onopen函数的主要内容,如果未能解决你的问题,请参考以下文章

在 Angularjs 中通过 WebSocket STOMP

Angular:使用 $window.history.back() 在 iOS 上并不总是有效

AngularJS:在服务中重新连接 WebSocket

AngularJS 和 Websocket

AngularJS - 在选项卡/窗口之间共享一个 websocket

WebSocket 握手 - 意外响应代码 200 - AngularJs 和 Spring Boot