Angular - Websocket 和 $rootScope.apply() [英] Angular - Websocket and $rootScope.apply()

查看:24
本文介绍了Angular - Websocket 和 $rootScope.apply()的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在使用一个 angular 应用程序,该应用程序使用 websocket 与后端进行通信.我在使 angular 的数据绑定正常工作时遇到了一些麻烦.

I'm currently playing around with an angular app that uses a websocket to communicate with the backend. I've had some trouble getting angular's data binding working correctly.

在下面的示例中,我创建了一个创建 websocket 连接的服务.如果 websocket 收到一条消息,我只是将该消息推送到一个包含所有接收到的消息的数组中.

In the example below I've created a service which creates the websocket connection. If the websocket receives a message I just push that message into an array which contains all of the received messages.

在我的控制器中,我将该消息数组绑定到作用域,然后使用 ng-repeat 在我的局部视图中列出它们.

In my controller I bind that array of messages to the scope and then use ng-repeat to list them all in my partial 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('MyCtrl1', ['$scope', 'MyService', function($scope, MyService) {
  $scope.messages = MyService.messages;
}])

部分:

<ul>
  <li ng-repeat="msg in messages">
      {{msg}} 
  </li>
</ul>

但是这不能正常工作.当收到一条新消息并将其推送到数组中时,应显示所有消息的列表不会更新.由于角度双向数据绑定,我预计它会更新.

This however does not work correctly. When a new message is received and pushed into the array, the list that should display all messages does not get updated. I expected it to be updated because of angular two way data binding.

我找到了一种解决方案,它通过将消息推送包装到服务中对 $rootScope.apply() 的调用中:

I've found one solution that works by wrapping the pushing of the message into a call to $rootScope.apply() in the service:

ws.onmessage = function(event) {
  $rootScope.$apply(function() {
    Service.messages.push(event.data);
  });
}  

我的问题是:

  1. 如果我不使用 $rootScope.apply(),我的列表不会自动更新,这是 angular 的预期行为吗?

  1. Is this the expected behavior of angular that my list does not automatically get updated if I do not use $rootScope.apply() ?

为什么我什至需要将它包装在 $rootScope.apply() 中?

Why do I even need to wrap it in $rootScope.apply()?

使用 $rootScope.apply() 是解决这个问题的正确方法吗?

Is using $rootScope.apply() the correct way to solve this?

对于这个问题,有没有比 $rootScope.apply() 更好的替代方法?

Are there better alternatives to $rootScope.apply() for this problem?

推荐答案

  1. 是的,AngularJS 的绑定是基于回合的",它们仅在某些 DOM 事件和对 $apply/$digest 的调用上触发.有一些有用的服务,例如 $http$timeout 可以为您完成包装,但 除此之外的任何事情都需要调用 $apply$digest.

  1. Yes, AngularJS's bindings are "turn-based", they only fire on certain DOM events and on calls to $apply/$digest. There are some useful services like $http and $timeout that do the wrapping for you, but anything outside of that requires calls to either $apply or $digest.

您需要让 AngularJS 知道您更改了绑定到作用域的变量,以便它可以更新视图.不过,还有其他方法可以做到这一点.

You need to let AngularJS know you've changed a variable that's bound to a scope so it can update the view. There are other ways to do this though.

这取决于你需要什么.当将您的代码包装在 $apply() 中时,AngularJS 将您的代码包装在内部 angularjs 日志记录和异常处理中,并且当它结束时,它会将 $digest 传播到您的所有控制器的范围.在大多数情况下,包裹在 $apply() 中是最好的方法,它为您可能最终使用的 angular 的未来功能打开了更多的大门.这是正确的方法吗?阅读下文.

It depends on what you need. When wrap your code in $apply(), AngularJS wraps your code in internal angularjs logging and exception handling, and when it's over, it propagates $digest to all of your controller's scopes. In most cases, wrapping in $apply() is the best way, it leaves more doors open for future features of angular you might end up to using. Is it the correct way? Read below.

如果您不使用 Angular 的错误处理,并且您知道您的更改不应传播到任何其他范围(根、控制器或指令),并且您需要优化性能,则可以调用 $digest 专门针对您的控制器的 $scope.这样,脏检查就不会传播.否则,如果您不希望 Angular 捕获错误,但需要脏检查传播到其他控制器/指令/rootScope,您可以,而不是用 $apply 包装,只需调用$rootScope.$apply() 在您进行更改之后.

If you don't use Angular's error handling, and you know your changes shouldn't propagate to any other scopes (root, controllers or directives), and you need to optimize for performance, you could call $digest on specifically your controller's $scope. This way the dirty-checking doesn't propagate. Otherwise, if you don't want errors to be caught by Angular, but need the dirty-checking to propagate to other controllers/directives/rootScope, you can, instead of wrapping with $apply, just calling $rootScope.$apply() after you made your changes.

进一步参考:$apply$digest

Further reference: $apply vs $digest

这篇关于Angular - Websocket 和 $rootScope.apply()的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆