Почему Angular выполняет функцию контроллера дважды для каждой модификации модели?

У меня есть приложение Angular из следующих уровней:

  • service() используется для вычислений и обработки данных
  • factory() используется как общее хранилище данных для нескольких контроллеров.
  • несколько controllers()

Мой контроллер предоставляет функцию из factory, которая, в свою очередь, вызывает функцию из службы. В HTML я запускаю функцию контроллера и вывод на экран пользователю: {{ controller.function() }}.

Я заметил, что при загрузке страницы и при каждом последующем изменении модели controller.function() выполняется дважды. Почему это происходит? Как я могу избежать ненужного вызова?

См. рабочий пример - откройте консоль JS вашего браузера, нажмите Run и обратите внимание, что строка console.log() выполняется два раза.


JavaScript

angular.module('myApp',[])
.service('Worker', [function() {
    this.i = 0;
    this.sample = function(data) {
    console.log(this.i.toString() + " " + Math.random().toString());
    return JSON.stringify(data);
  };
}])
.factory('DataStorage', ['Worker', function(worker) {
    var self = this;
    self.data = [{}, {}];
    self.getData = function() {
      return self.data;
    }
  self.sample = function() {
    return worker.sample(self.data);
  };
  return {
    getData: self.getData,
    sample: self.sample
  };
}])
.controller('MainController', ['DataStorage', function(DataStorage) {
    var self = this;
    self.data = DataStorage.getData();
  self.sample = DataStorage.sample;
}])
.controller('DataSource', [function() {
  var self = this;
  self.data = ["one", "two", "three", "four", "five", "six"];
}])

HTML

<!DOCTYPE html>
<html ng-app="myApp">

  <head>
    <script data-require="[email protected]" data-semver="1.5.8" src="https://opensource.keycdn.com/angularjs/1.5.8/angular.min.js"></script>
    <script src="script.js"></script>
  </head>

  <body ng-controller="MainController as main">
    <div ng-controller="DataSource as datasource">
      <div ng-repeat="select in main.data">
        <select ng-model="select.choice" ng-options="value for value in datasource.data">
          <option value="">-- Your choice --</option>
        </select>
      </div>

    <pre>
      {{ main.sample() }}
    </pre>
  </div>
  </body>

</html>

Почему эта функция запускается несколько раз для каждой отдельной модели и как я могу убедиться, что она работает только один раз?

Я попытался назначить вывод функции factory в переменную контроллера (и использовать {{ controller.function }} в HTML - отметить отсутствие круглых скобок), но тогда функция запускается только один раз. Он должен работать с новыми данными при изменении модели.

Аналогичные проблемы, описанные в StackOverflow, относятся к модулю ng-route, который я не использую.

Ответ 1

Это происходит потому, что вы вызываете функцию sample() в выражении следующим образом:

{{ main.sample() }}

Эта функция будет вызываться как минимум дважды, если вы используете подобное выражение.

Причина состоит в том, что Angular запускает цикл дайджест, пока все не будет обновлено (это будет, по крайней мере, дважды). В вашем случае он запускается в первый раз, чтобы вернуть значение и второй раз, чтобы проверить, остались ли какие-либо изменения.

Вы можете гарантировать, что он запускается только один раз, если вместо этого вы поместите свою функцию в директиву ng-change.

В вашем случае это будет:

 <select ng-model="select.choice" ng-change="main.sample()" ng-options="value for value in datasource.data">
      <option value="">-- Your choice --</option>
 </select>