AngularJS 不使用 socket.io 刷新视图

Posted

技术标签:

【中文标题】AngularJS 不使用 socket.io 刷新视图【英文标题】:AngularJS does not refresh view with socket.io 【发布时间】:2016-07-05 10:40:33 【问题描述】:

我有一个带有以下设置的 node.js 服务器应用程序:

    var express = require('express');
    var io = require('socket.io');
    var http = require('http');
    var app = express();

    app.use(express.static('public'));

    var server = http.createServer(app);
    io = io.listen(server); 

    io.on('connection', function(socket)
        console.log('a user is connected');
    );

    device.on('disconnect', function() 
        console.log('we got disconnected! :( '); 
        io.emit('deviceDisconnection');    
    );

这里的设备是蓝牙连接的设备。 而且,在客户端,我有一个 AngularJS 应用程序,在应用程序的控制器中声明了以下事件订阅:

var appFront = angular.module(appFront , [])
.controller('mainController', ['$scope', '$http', function($scope,$http)     
var socket = io();  
    socket.on('deviceDisconnection', function()
      $scope.connected = 'TRUE';
    );
]);

当然,在视图中,我有以下绑定:

<div class="row">
  <p>connected</p>
</div>

问题在于更改并不是真正“实时”的。我的意思是,connected 值可能在范围内发生了更改,但需要在页面上执行操作(按钮 clic)以使用正确的值更新视图。如果我没有在页面上执行任何操作,则不会刷新值。

我可能忘记了什么..但我不知道是什么..

【问题讨论】:

【参考方案1】:

Socket.io 事件是 AngularJS 的外部事件,因此您需要警告 AngularJS 刚刚发生了变化:

var appFront = angular.module(appFront , [])
.controller('mainController', ['$scope', '$http', function($scope,$http)     
var socket = io();  
    socket.on('deviceDisconnection', function()
      $scope.$applyAsync(function () 
         $scope.connected = 'TRUE';
      );
    );
]);

现在这可能很麻烦,所以你可以创建一个工厂来为你处理它

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);
          
        );
      )
    
  ;
);

您可以在here 中查看有关该代码 sn-p 的更多信息,感谢作者 Brian Ford。

编辑

正如maurycy所说,既然Angular 1.3最好用$applyAsync,而且上面的sn-p是2012年写的,有点过时了,所以更好的版本应该是这样的

app.factory('socket', function ($rootScope) 
  var socket = io.connect();
  return 
    on: function (eventName, callback) 
      socket.on(eventName, function ()   
        var args = arguments;
        $rootScope.$applyAsync(function () 
          callback.apply(socket, args);
        );
      );
    ,
    emit: function (eventName, data, callback) 
      socket.emit(eventName, data, function () 
        var args = arguments;
        $rootScope.$applyAsync(function () 
          if (callback) 
            callback.apply(socket, args);
          
        );
      )
    
  ;
);

【讨论】:

我的错,错过了。好东西 :) 坦率地说,这是最好的解决方案,将 socket.io 包装为 Angular 服务使其更容易 @maurycy 为作者添加了更多可见的学分,并添加了一个版本,您建议使用$applyAsync【参考方案2】:

Angular 不知道其上下文之外的变化。要解决这个问题,您应该像这样使用$apply

    var appFront = angular.module(appFront , []).controller('mainController', ['$scope', '$http', function($scope,$http)     
        var socket = io();  

        socket.on('deviceDisconnection', function()
            $scope.$apply(function () 
                $scope.connected = 'TRUE';
            );

        );

    ]);

$scope.$apply() 将执行作为参数传递的函数,然后调用 $scope.$digest() 来更新任何绑定或观察者。

【讨论】:

从 Angular 1.3 开始使用 $scope.$applyAsync 更适合此目的【参考方案3】:

因为socket事件在AngularJS之外,所以需要消化作用域:

socket.on('deviceDisconnection', function()
      $scope.connected = 'TRUE';
      $scope.$digest();
);

您可以阅读this interesting article 以真正了解为什么需要这样做

【讨论】:

不要把$scope.$digest()放在你的代码中,如果应用程序增长并且$digest会更频繁地被触发,它会抛出JS错误$digest in progres使用$scope.$apply或更新版本的angularjs $scope.$applyAsync 这就是为什么在 angular 1.3 之前人们在不指定时间的情况下使用 $timeout 欺骗它,从 angular 1.3 开始,applyAsync 就是为此设计的 好的。我不知道 applyAsync。

以上是关于AngularJS 不使用 socket.io 刷新视图的主要内容,如果未能解决你的问题,请参考以下文章

改进这个 AngularJS 工厂以与 socket.io 一起使用

如何使用 Express、AngularJS、Socket.io 广播和获取通知?

AngularJS:通过 https 使用 socket.io 的聊天应用程序

Angularjs 中的 Socket.io

Angularjs socket.io 服务

使用 angularjs 和 socket.io 实时保存和显示评论