Контроллер с методом ngResource вызывается бесконечно

Я решил начать изучение AngularJS с создания простого приложения.

Приложение на стороне сервера создано с помощью ExpressJ, но ресурс, используемый ниже (/movie/:id), еще не реализован, поэтому указание на этот URL приведет к ошибке 404 (не найдено). ) ошибка. Так что работает только получение '/'.

Я хотел посмотреть, как ведет себя $resource, поэтому я сделал простой тест:

var app = angular.module("app", ["ngResource"]);

app.factory("Movie", function ($resource) {
    return $resource("/movie/:id");
})

app.controller("MovieCtrl", function($scope, Movie) {
    $scope.test = function () {
        Movie.query();
        return 42;
    } 
});

И мой файл шаблона:

<div ng-app="app">
    <div ng-controller="MovieCtrl">
        {{ test() }}
    </div>
</div>

Как и ожидалось, шаблон отображается, и «42» отображается правильно, но если я смотрю консоль в инструментах разработчика Chrome, я продолжаю видеть следующую ошибку (также, как и ожидалось):

GET http://localhost/movie 404 (Not Found)

Но это сообщение печатается бесконечно и никогда не останавливается, как будто мой ресурс Movie продолжает пытаться получить доступ к /movie, хотя после сотен попыток он все еще терпит неудачу.

Заранее спасибо.


person Laurent Dezitter    schedule 21.06.2013    source источник


Ответы (1)


Это связано с тем, что Movie.query() вызывает $scope.$apply() после получения ответа от сервера.

Каждый раз, когда вызывается $scope.$apply(), angular выполняет грязную проверку (которая снова вызывает test и, следовательно, снова вызывает Movie.query()), чтобы узнать, изменилось ли что-нибудь. Это вызывает бесконечный цикл.

переместите Movie.query() из test(), и это должно сработать.

Поясню — взгляните на этот псевдокод:

var watches = ['$scope.test()'];
var previous = {};
var values = {};

$rootScope.$apply = function(){
  previous = values;
  values = {};
  var dirty = false;  
  for (var i =0;i<watches.length;i++){
      var expression = watches[i];
      values[expression] = value = eval(expression);
      if(value!=previous)dirty=true;
  }
  if(dirty)$rootScope.$apply();
}

Movie.query = function(){
   setTimeout(function(){
      $rootScope.$apply();
   },300);
}

$scope.test = function(){
   Movie.query();
   return 42;
}

поэтому поток следующий:

  1. $scope.apply();
  2. $scope.тест();
  3. Кино.запрос(); -> setTimeout($scope.apply,100) (назад к началу);

и так далее..

person g00fy    schedule 21.06.2013
comment
Выполняется ли грязная проверка, чтобы убедиться, что результат возвращаемого метода тестирования не изменился? Если да, то Movie.query() не изменяет этот результат. - person Laurent Dezitter; 22.06.2013
comment
Да, но Movie.query() запускает $scope.$apply() (когда данные возвращаются с сервера), который проверяет, изменился ли test(). Во время этой проверки test() запускает другой Movie.query(), который снова запускает scope.$apply() и так далее. - person g00fy; 22.06.2013