На онлайн-курсах Angular под руководством экспертов вы не можете пройти мимо Ultimate Angular от Todd Motto. Попробуйте его курсы здесь и используйте код SITEPOINT, чтобы получить скидку 25% и помочь в поддержке SitePoint.
$apply()
$digest()
Чтобы понять, как работает AngularJS, нужно полностью понять, как работают $apply()
$digest()
Цель этой статьи — объяснить, что $apply()
$digest()
$apply
$digest
scope
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
Цикл $digest
scope
Предположим, что вы изменяете модель $digest
$digest
В этом случае AngularJS автоматически запускает цикл $scope.$digest()
scope
Когда начинается цикл ng-click
Эти наблюдатели проверяют, отличается ли текущее значение модели области $digest
Если да, то соответствующая функция слушателя выполняется. В результате, если у вас есть какие-либо выражения в представлении, они будут обновлены. В дополнение к $digest()
$digest
scope
ng-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()