Подтвердить что ты не робот

Angular - Websocket и $rootScope.apply()

В настоящее время я играю с приложением angular, которое использует 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>

Это, однако, работает неправильно. Когда новое сообщение принимается и вводится в массив, список, который должен отображать все сообщения, не обновляется. Я ожидал, что он будет обновлен из-за angular двусторонней привязки данных.

Я нашел одно решение, которое работает путем переноса нажатия сообщения в вызов $rootScope.apply() в службе:

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

Мои вопросы:

  • Является ли это ожидаемым поведением angular, что мой список не обновляется автоматически, если я не использую $rootScope.apply()?

  • Почему мне даже нужно обернуть его в $rootScope.apply()?

  • Использует $rootScope.apply() правильный способ решить эту проблему?

  • Есть ли лучшие альтернативы $rootScope.apply() для этой проблемы?

4b9b3361

Ответ 1

  • Да, привязки AngularJS являются "пошаговыми", они запускаются только при определенных событиях DOM и при звонках на $apply/$digest. Для этого есть несколько полезных сервисов, таких как $http и $timeout, но что-либо за пределами этого требует вызовов либо $apply, либо $digest.

  • Вы должны позволить AngularJS знать, что вы изменили переменную, связанную с областью, чтобы она могла обновлять представление. Есть и другие способы сделать это, хотя.

  • Это зависит от того, что вам нужно. Когда вы завершаете свой код в $apply(), AngularJS обертывает ваш код во внутреннем журнале и обработке исключений, а когда он заканчивается, он распространяет $digest на все области вашего контроллера. В большинстве случаев упаковка в $apply() является наилучшим способом, она оставляет больше дверей открытыми для будущих функций angular, которые могут закончиться использованием. Правильно ли это? Читайте ниже.

  • Если вы не используете обработку ошибок angular, и знаете, что ваши изменения не должны распространяться на другие области (корневые, контроллеры или директивы), и вам нужно оптимизировать производительность, вы можете позвонить $digest на вашем контроллере $scope. Таким образом, грязная проверка не распространяется. В противном случае, если вы не хотите, чтобы ошибки были пойманы с помощью Angular, но вам нужна грязная проверка для распространения на другие контроллеры/директивы/rootScope, вы можете вместо обертывания с помощью $apply просто позвонить $rootScope.$apply() после внесения изменений.

Дальнейшая ссылка: $apply vs $digest