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 广播和获取通知?