一尘不染

Angular-Websocket和$ rootScope.apply()

angularjs

我目前正在玩一个使用websocket与后端通信的有角度的应用程序。我在使angular的数据绑定正常工作时遇到了一些麻烦。

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

在我的控制器中,我将该消息数组绑定到作用域,然后用于ng-repeat在我的局部视图中列出所有消息。

服务:

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>

但是,这不能正常工作。收到新消息并将其推送到数组时,应显示所有消息的列表不会得到更新。我期望它会由于角度双向数据绑定而被更新。

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

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

我的问题是:

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

  2. 为什么什至需要将其包装$rootScope.apply()

  3. 是否使用$rootScope.apply()正确的方法来解决此问题?

  4. 有更好的替代方法来$rootScope.apply()解决此问题吗?


阅读 274

收藏
2020-07-04

共1个答案

一尘不染

  1. 是的,AngularJS的绑定是“基于回合的”,它们仅在某些DOM事件以及对$apply/的调用时触发$digest。有一些有用的服务,例如$http$timeout,它们可以为您做包装,但除此之外的任何东西都需要调用$apply$digest

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

  3. 这取决于您的需求。将代码包装到时$apply(),AngularJS将代码包装到内部angularjs日志记录和异常处理中,当结束时,它将传播$digest到控制器的所有作用域。在大多数情况下,包裹$apply()是最好的方法,它为将来可能要使用的角度功能留出了更多的空间。这是正确的方法吗?参见下文。

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

进一步参考:
$applyvs$digest

2020-07-04