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

Увеличивает ли метод $scope и $$ фаза работы, как и ожидалось в AngularJS?

Одна важная вещь, которую следует иметь в виду при работе с инструментами сторонних разработчиков, а также внешними событиями DOM в AngularJS, заключается в использовании операции метода $scope.$apply() для запуска изменений. Это работает потрясающе, но иногда сама область, которую я уже измельчаю через дайджест (в основном это триггеры $apply), и при вызове $apply, когда это происходит, выдает ошибку. Поэтому, чтобы обойти это, вам нужно будет обратить внимание на флаг $scope.$$phase, который устанавливается в область всякий раз, когда происходит дайджест.

Итак, скажем, вы хотите изменить URL-адрес, и вы запустите его:

$scope.$apply(function() {
  $location.path('/home');
});

И это работает так, как ожидалось, но теперь давайте предположим, что $scope занят этим. Поэтому вместо этого вы проверяете переменную фазы $$ и предполагаете, что ваши изменения будут подняты:

if($scope.$$phase) {
  $location.path('/home');
}
else {
  $scope.$apply(function() {
    $location.path('/home');
  });
}

Это то, что я делал (очевидно, не с дублированием кода), и, похоже, он работает в 100% случаев. Что меня беспокоит, так это то, что как AngularJS набирает изменения, когда область действия находится на полпути к ее перевариванию?

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

<div class="binding">{{ binding1 }}</div>
<div class="binding">{{ binding2 }}</div>
<div class="binding">{{ binding3 }}</div>
<div class="binding">{{ binding4 }}</div>
<div class="binding">{{ binding5 }}</div>
<div class="binding">{{ binding6 }}</div>
<div class="binding">{{ binding7 }}</div>
<div class="binding">{{ binding8 }}</div>

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

if($scope.$$phase) {
  $scope.binding1 = 'henry';
}

Теперь, каким-то образом, AngularJS подбирает изменения и правильно обновляет привязку. Даже если само изменение можно считать более ранним в очереди по отношению к HTML/DOM.

Мой вопрос: как AngularJS управляет этим потенциальным состоянием гонки? Мне может быть комфортно, если обновление binding8 (так как оно ниже страницы), но поскольку binding1 также обновляется (сразу же без необходимости повторного вызова $apply), это делает меня немного потерянным. Означает ли это, что другое переваривание было отправлено где-то посередине? Или объект $scope более волшебный, чем я ожидаю? Я бы предположил, что эта проблема была до сих пор, но так как выяснение порядка $$ phase и $scope в первую очередь было немного сложным, я предполагаю, что это тоже может быть чем-то, что попало в трещины.

Любые идеи?

4b9b3361

Ответ 1

Относительно привязок и условий гонки. $digest будет зацикливать всех наблюдателей, пока не будет никаких изменений. Как вы можете наблюдать, добавляя журналы к наблюдателям/связанным методам, он будет вызывать каждую привязку/наблюдателя по крайней мере дважды, чтобы убедиться, что изменений нет, и все привязанные значения являются стабильными. Это только грязные проверки, которые выполняются до тех пор, пока не будет разрешено каждое значение (которое не изменилось в течение двух итераций цикла). Надеюсь, что это поможет.

Это объясняется в документах AngularJS здесь: http://docs.angularjs.org/api/ng.$rootScope.Scope#$digest

ПРИМЕЧАНИЕ. Это копия/вставка моего комментария по запросу matsko.

Ответ 2

Apply будет продолжать звонить digest, пока он не уверен, что ничего не изменилось. Таким образом, если при первом вызове может быть состояние гонки, но вторая всегда будет компенсироваться.

Ответ 3

Вы не должны использовать это обходное решение в любом случае: если состояние вашего $scope не определено в этой функции, вы должны переварить его выше в стеке вызовов, где вы знаете, если вы синхронизированы с помощью angular, таким образом нет необходимости переваривать, или если вы модифицируете модель асинхронно, чтобы вы могли ее переварить.

На стороне примечание $scope.$apply в основном представляет собой $scope.$root.$digest с обработкой ошибок, поэтому, если вы обновляете изолированную область действия в директиве, вы можете сохранять показатели, вызывая $digest вместо $apply:

// Somewhere in a callback
$location.path('/home');
$scope.$digest();

PS: Для исправления ответа e-satis: $digest также будет вызывать себя, пока область действия загрязнена.