我目前正在使用一个 Angular 应用程序,它使用 websocket 与后端进行通信。我在让 Angular 的数据绑定(bind)正常工作时遇到了一些麻烦。
在下面的示例中,我创建了一个用于创建 Websocket 连接的服务。如果 websocket 收到一条消息,我只需将该消息推送到一个包含所有收到消息的数组中。
在我的 Controller 中,我将该消息数组绑定(bind)到范围,然后使用 ng-repeat
在我的部分 View 中列出它们。
服务:
factory('MyService', [function() {
var wsUrl = angular.element(document.querySelector('#ws-url')).val();
var ws = new WebSocket(wsUrl);
ws.onopen = function() {
console.log("connection established ...");
}
ws.onmessage = function(event) {
Service.messages.push(event.data);
}
var Service = {};
Service.messages = [];
return Service;
}]);
Controller :
controller('MyCtrl1', ['$scope', 'MyService', function($scope, MyService) {
$scope.messages = MyService.messages;
}])
部分:
<ul>
<li ng-repeat="msg in messages">
{{msg}}
</li>
</ul>
但是这不能正常工作。当收到新消息并将其插入数组时,应显示所有消息的列表不会更新。由于 Angular 双向数据绑定(bind),我预计它会被更新。
我找到了一种解决方案,可以将消息推送包装到服务中对 $rootScope.apply()
的调用中:
ws.onmessage = function(event) {
$rootScope.$apply(function() {
Service.messages.push(event.data);
});
}
我的问题是:
如果我不使用
$rootScope.apply()
,我的列表不会自动更新,这是否是 Angular 的预期行为?为什么我需要将其包装在
$rootScope.apply()
中?使用
$rootScope.apply()
是解决此问题的正确方法吗?对于这个问题,有比
$rootScope.apply()
更好的替代方法吗?
最佳答案
是的,AngularJS 的绑定(bind)是“回合制”的,它们仅在某些 DOM 事件和对
$apply
/$digest
的调用上触发。有一些有用的服务,例如$http
和$timeout
可以为您进行包装,但是 anything outside of that requires calls to either$apply
or$digest
.您需要让 AngularJS 知道您已经更改了绑定(bind)到范围的变量,以便它可以更新 View 。不过还有其他方法可以做到这一点。
这取决于您的需要。当将代码包装在
$apply()
中时,AngularJS 将您的代码包装在内部 AngularJS 日志记录和异常处理中,当它结束时,它会将$digest
传播到所有 Controller 范围。在大多数情况下,包装在$apply()
中是最好的方法,它为您最终可能使用的 Angular future 功能留下了更多机会。这是正确的方法吗?请阅读下文。如果您不使用 Angular 的错误处理,并且您知道您的更改不应传播到任何其他范围(根、 Controller 或指令),并且您需要优化性能,则可以调用
$digest
专门针对您的 Controller 的$scope
。这样脏检查就不会传播。否则,如果您不希望 Angular 捕获错误,但需要脏检查传播到其他 Controller /指令/rootScope,您可以不使用 $apply
包装,而只需调用进行更改后$rootScope.$apply()
。
进一步引用:
$apply
vs $digest
关于javascript - Angular - Websocket 和 $rootScope.apply(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21658490/