Статьи

Понимание Angular’s $ apply () и $ digest ()

На онлайн-курсах Angular под руководством экспертов вы не можете пройти мимо Ultimate Angular от Todd Motto. Попробуйте его курсы здесь и используйте код SITEPOINT, чтобы получить скидку 25% и помочь в поддержке SitePoint.

$apply()$digest() Чтобы понять, как работает AngularJS, нужно полностью понять, как работают $apply()$digest() Цель этой статьи — объяснить, что $apply()$digest()$apply

$digestscope

AngularJS предлагает невероятно удивительную функцию, известную как двухстороннее связывание данных, которая значительно упрощает нашу жизнь. Привязка данных означает, что при изменении чего-либо в представлении модель области автоматически обновляется. Точно так же, всякий раз, когда изменяется модель области, представление обновляется с новым значением. Как AngularJS делает это? Когда вы пишете выражение ( scope Этот {{aModel}}

 scope

Второй аргумент, передаваемый в watcher$scope.$watch('aModel', function(newValue, oldValue) {
//update the DOM with newValue
});
Нам легко понять, что при изменении значения $watch() Но есть еще один большой вопрос! Как Angular определяет, когда вызывать эту функцию слушателя? Другими словами, как AngularJS узнает, когда aModel Периодически ли запускается функция, чтобы проверить, изменилось ли значение модели области? Ну вот и начинается цикл aModel

Это цикл aModel Когда запускается наблюдатель, AngularJS оценивает модель scope Итак, наш следующий вопрос — когда и как начинается этот цикл $digest

Цикл $digestscope Предположим, что вы изменяете модель $digest$digest В этом случае AngularJS автоматически запускает цикл $scope.$digest()scope Когда начинается цикл ng-click Эти наблюдатели проверяют, отличается ли текущее значение модели области $digest Если да, то соответствующая функция слушателя выполняется. В результате, если у вас есть какие-либо выражения в представлении, они будут обновлены. В дополнение к $digest()$digestscopeng-click

Все идет нормально! Но есть маленькая ошибка. В вышеупомянутых случаях Angular напрямую не вызывает ng-model Вместо этого он вызывает $timeout$digest$digest()$scope.$apply() В результате этого в $rootScope.$digest()

Теперь давайте предположим, что вы прикрепили директиву $rootScope Когда кнопка нажата, AngularJS переносит вызов функции в ng-click Итак, ваша функция выполняется как обычно, меняйте модели (если есть), и начинается цикл $scope.$apply()

Примечание : $digest$scope.$apply()$rootScope.$digest()$apply() Функция $digest Первый принимает функцию в качестве аргумента, оценивает ее и запускает цикл $digest Вторая версия не принимает никаких аргументов и просто запускает цикл $apply() Мы увидим, почему первый вариант предпочтительнее в ближайшее время.

Когда вы звоните $apply()

Если AngularJS обычно оборачивает наш код в $digest$apply()$apply() На самом деле AngularJS проясняет одну вещь. Он будет учитывать только те изменения модели, которые выполняются в контексте AngularJS (т. Е. Код, который изменяет модели, обернут в $apply() Встроенные директивы Angular уже делают это, так что любые сделанные вами изменения в модели отражаются в представлении. Однако, если вы измените какую-либо модель вне контекста Angular, вам необходимо сообщить Angular об изменениях, вызвав watchers Это все равно, что сказать Angular, что вы меняете некоторые модели, и он должен запустить setTimeout()

Например, если вы используете функцию JavaScript scope В этом случае вы обязаны вручную вызывать $apply()$digest Аналогично, если у вас есть директива, которая устанавливает прослушиватель событий DOM и изменяет некоторые модели внутри функции-обработчика, вам нужно вызвать $apply()

Давайте посмотрим на пример. Предположим, у вас есть страница, и после загрузки страницы вы хотите отобразить сообщение после двухсекундной задержки. Ваша реализация может выглядеть как JavaScript и HTML, показанные в следующем листинге.

Запустив пример, вы увидите, что отложенная функция запускается после двухсекундного интервала и обновляет scope Тем не менее, вид не обновляется. Причина, как вы уже догадались, в том, что мы забыли вызвать message Поэтому нам нужно обновить нашу функцию $apply()

Если вы запустите этот обновленный пример, вы увидите обновление представления через две секунды. Единственное изменение заключается в том, что мы обернули наш код в getMessage()$scope.$apply()$rootScope.$digest()$timeout В результате наблюдатели увольняются как обычно, и представление обновляется.

Примечание . Между прочим, вы должны по возможности использовать службу setTimeout()$apply()$apply()$apply()

Кроме того, обратите внимание, что в приведенном выше коде вы могли бы сделать изменения модели как обычно и поместить в конце вызов $scope.getMessage = function() {
setTimeout(function() {
$scope.message = 'Fetched after two seconds';
console.log('message:' + $scope.message);
$scope.$apply(); //this triggers a $digest
}, 2000);
};
Посмотрите на следующий фрагмент:

 $apply()

Приведенный выше код использует безусловную версию $apply() Помните, что вы всегда должны использовать версию $apply() Это происходит потому, что когда вы передаете функцию в try...catch$exceptionHandler$digest

Сколько раз выполняется цикл $digest

Когда выполняется цикл scope Если они есть, то соответствующие функции слушателя вызываются. Это приводит к важному вопросу. Что если функция слушателя сама изменила модель scope Как AngularJS объяснит это изменение?

Ответ в том, что цикл $digest В конце токовой петли она начинается заново, чтобы проверить, изменилась ли какая-либо из моделей. Это в основном грязная проверка, которая делается для учета любых изменений модели, которые могли быть сделаны функциями слушателя. Таким образом, цикл $digest

Примечание . Как минимум, $digest Как уже говорилось выше, он запускается еще раз, чтобы убедиться, что модели стабильны и изменений нет.

Вывод

Я надеюсь, что эта статья прояснила, что такое $apply$digest Самое важное, что нужно иметь в виду, — может ли Angular обнаруживать ваши изменения. Если это невозможно, вы должны вызвать $apply()