javascript - Angular - Websocket 和 $rootScope.apply()

标签 javascript angularjs websocket

我目前正在使用一个 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);
  });
}  

我的问题是:

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

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

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

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

最佳答案

  1. 是的,AngularJS 的绑定(bind)是“回合制”的,它们仅在某些 DOM 事件和对 $apply/$digest 的调用上触发。有一些有用的服务,例如 $http$timeout 可以为您进行包装,但是 anything outside of that requires calls to either $apply or $digest .

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

  3. 这取决于您的需要。当将代码包装在 $apply() 中时,AngularJS 将您的代码包装在内部 AngularJS 日志记录和异常处理中,当它结束时,它会将 $digest 传播到所有 Controller 范围。在大多数情况下,包装在 $apply() 中是最好的方法,它为您最终可能使用的 Angular future 功能留下了更多机会。这是正确的方法吗?请阅读下文。

  4. 如果您不使用 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/

相关文章:

javascript - Angularjs & karma Controller 单元测试注入(inject)器 :modulerr

javascript - 使用 $q.all 的 Angular Promises

spring - 尝试通过 websocket 转换和发送时出现空指针异常

javascript - react Hook : Can't send state from Child component to Parent component

javascript - 从 ReactJS 中导入的函数更改类状态

javascript - 如何将日期转换为时间

angularjs - Cordova 文件插件的目录错误

javascript - 如果使用 Javascript 选择复选框,如何要求输入字段?

python - 可以在共享托管 Web 服务器上使用 websockets 吗?

ajax - Web 套接字会让 ajax/CORS 过时吗?