Рубрики
Без рубрики

Смотреть, WatchGroup, Watchcollection и Deep Watching в Angularjs 1.x

Пост Я опубликовал обратно в день, который делает глубокий погружение во многие слои обнаружения изменений в приложениях угловых 1.x.

Автор оригинала: Jonathan Milgrom.

Мой оригинальный пост можно найти здесь.

Многие слои обнаружения изменения

Пользователь нажимает кнопку «UPVote»,

1 * KU6Q7PI0COOVXXIOY8UAEW.PNG

Попытка увеличить количество голосов до 1034. Действие $ apply’ded через NG-Click


будет вызывать цикл $ digest под капотом, который проверяет все зарегистрированные $ Watches для изменений. Затем выражение, обеспечивающее «проголосовал» стиль для ответов, зарегистрированных через NG-класс



и выражение, обеспечивающее совокупное количество голосов, зарегистрированных через двойные фигурные скобки {{}}



 {{ vm.answer.voteCount() }}


будет вызвать подходящие обновления DOM:

1 * cxhexiunyszze80r08l5a.png.

Обнаружение изменений является фундаментальной частью приложений AngularJS. Использование местных директив Angularjs или построение собственного собственного, понимание многих слоев наблюдения данных имеет важное значение для понимания угловых.

Какой-то интересный (но прокинуемый) фон

Угловое выражение может производить разные значения со временем. Смотря наблюдение за получением ценности этого выражения и выполнения задачи, когда она изменилась. И в угловом угловом углу выражение может принять форму строки или функции JavaScript:

  1. любой ol ‘javaScript функция
scope.greeting = 'hi there';

var getGreeting = function(scope) {
  return scope.greeting;
};
scope.$watch(getGreeting, function(greeting) {
  console.log('greeting: ', greeting); // greeting: hi there
});
  1. нить
scope.greeting = 'hi there';

scope.$watch('greeting', function(greeting) {
  console.log('greeting: ', greeting); // greeting: hi there
});

Функция или … строка? Внутренне, первое, что будет использоваться. $ Способ, это Пройдите свой первый параметр на службу $ Parse Отказ Сервис $ Parse – это функция, которая возвращает другую функцию (давайте назовем ее «PARSEFN»). PARSEFN ожидает, что нужно вызывать с желаемым объектом контекста, на который может быть оценена исходная строка или функция.

var context = {first: 'steph', last: 'curry'};

// with string
var string = 'last + ", " + first';
var parseFn = $parse(string);
parseFn(context); // => curry, steph

// with function
var func = function(context) {
  return context.last + ', ' + context.first;
};
var parseFn = $parse(func);
parseFn(context); // => curry, steph

Если служба $ Parse получает строку, Работа должна быть выполнена Чтобы перевести строку в правильный JavaScript, способный к оценке против объекта I.e. Функция. С другой стороны, если он получает функцию, ну … не очень хочет случиться Отказ Поскольку служба получила то, что он должен производить, это может предположить, что функция была правильно подготовлена. Как видите, большая часть угловой «магии» находится в анализе параметра строки в такую функцию, чтобы включить потребление строки.

В любой момент времени Отказ Существует причина, причина угла выбрала структуру функции, с контекстом-объектом-параметром: вызовы функции выявляют изменения в базовом контексте, что означает, что функция может быть вызвана в любой момент времени для получения значения основного выражения или функция в такое время:

var fullName = 'last + ", " + first';
var getFullName = $parse(fullName); // getFullName is the parseFn!

var context = {first: 'steph', last: 'curry'};
getFullName(context); // => curry, steph
context = {first: 'russ', last: 'westbrook'};
getFullName(context); // => westbrook, russ

Поскольку объекты охвата являются … объекты, это, конечно, работает с объектами объема. String ‘vm.answer.isvotedfor (vm.user) из пример вышеупомянутой – после того, как передается в анализ часов и преобразован в функцию, которая готова принять объект – был готов к раскрытию любой новый isvotedfor отражается в обновленном объекте объема. Теперь структура функции, возвращающаяся на функцию службы тарифа, которая также начинает иметь смысл. Возвращенная функция (I.e Parsefn), подготовлена и готовая принять последний объект Scope, это именно то, что потребности в диварей и Именно то, что он получает Для того, чтобы получить последнее значение выражения. Разумно, Parsefn назван «получить» внутренне Из-за этих ездовых качеств.

Против последней кэшированной ценности Отказ Теперь, чтобы определить изменение, все цикл $ digest осталось сделать, это кэш последним значением, полученным зарегистрированным Parsefn и сравнить его с следующим …. Ничто привело нас к теме этого поста: это сравнение между новыми и старыми ценностями: Что представляет собой равенство и множество уровней обнаружения изменения в угловом углу.

$ Watch – Тип 1

Самый простой и наиболее распространенный, этот тип часов использует JavaScript для сравнения старых и новых значений, вызывающих обратный вызов только после строгого неравенства:

scope.$watch('greeting', function(greeting) {
  console.log('greeting: ', greeting);
});

scope.greeting = 'hi there'; // greeting: hi there

$timeout(function() { scope.greeting += ', Joe'}); // greeting: hi there, Joe

Для выражений, которые оценивают на примитивные типы, такие как строки и цифры, это имеет предсказуемый эффект. Старые и новые значения 4 и 4 считаются равными, но 4 и 5 и 4 и «4» нет. Точно так же «привет» и «Hello» не будет зарегистрировать изменения, но «привет» и «до свидания». В приведенном выше примере «Упвита» вьющиеся в курсовые кронштейны {{}} зарегистрировали этот тип часов для выражения vm.answer.voteCount (). Когда 1034 было сравнено на 1033, изменение было зарегистрировано.

Для выражений, которые оценивают на объекты JavaScript, строгое равенство означает что-то менее интуитивно понятное. Тот же объект, независимо от того, насколько мутирован между проверками равенства, не будет зарегистрировать «изменение», тогда как два разных объекта, независимо от того, насколько похоже, будет:

scope.$watch('obj1', function callback(newValue) {
  console.log('obj1: ', newValue);
});

// (when initialized) prints out: undefined

$timeout(function() {
  scope.obj1 = {name: 'jonathan'}; // prints out: {name: 'jonathan'}
});

$timeout(function() {
  scope.obj1.name = 'michael'; // no "change" registered, no print out
}, 500);

$timeout(function() {
  scope.obj1.age = 30; // no "change" registered, no print out
}, 1000);

$timeout(function() {
  // it's a new object! 
  scope.obj1 = {name: 'jonathan'}; // prints out: {name: 'jonathan'}
}, 1500);

Преимущества и ограничения WatchTheThe Важно отметить, что при определении того, как изменение зарегистрировано, не так ли два объекта одинаковые свойства, но могут ли два объекта относятся к одному и тому же адресу в памяти I.e, являются ли они того же объекта. Уведомление в приведенном выше примере, что разные объекты с точно такими же свойствами и значениями, тем не менее, регистрируются изменения и печатают на консоль с новейшим объектом, поскольку они являются разными объектами. Принимая во внимание, что та же ссылка на объект отпечатывает ничего к консоли, независимо от того, насколько мутированы между проверками равенства.

$ watchgroup – тип 2

Этот тип часов может обрабатывать несколько выражений вместо того, чтобы ограничиваться только одним, вызывающим зарегистрированный обратный вызов, когда любая из выражений изменилась.

scope.$watchGroup(['expression1', 'expression2'], function(arrayOfExpressions) {
  ...
});

Вы можете использовать этот тип часов, если связаны два или более свойства. В приведенном выше примере «UPVote» вы можете использовать эти часы, чтобы отключить дальнейшее голосование, если ответ был проголосован или против:

var isVotedGroup = [
  'vm.answer.isVotedAgainst(vm.user)',
  'vm.answer.isVotedFor(vm.user)'
];

var unwatch = scope.$watchGroup(isVotedGroup, function(isVotedGroup) {
  var hasVoted = isVotedGroup.some(function(bool) {
    return bool;
  });
  if (hasVoted) {
    vm.answer.disableVoting(vm.user);
    unwatch();
  } 
});

Важно отметить, что сам содержащий массив не смотрит на WatchGroup в резком контрасте (может быть, более знакомой) WatchCollection; Скорее, каждый член массива. Как и тему регулярного часа 1 типа 1, каждый элемент массива может сам быть строковым выражением, способным на контекстную оценку или функцию, готовую к передаче объекта контекста. В результате WatchGroup можно рассматривать как просто способ объединить несколько постоянных часов 1-го уровня с одним функцией обратного вызова. Когда любая из групповых часов регистрирует изменение, вызывается обратный вызов. Эта настройка имеет преимущество, позволяющее выражениям быть членами группы, как описано. Но члены группы не могут быть динамически добавлены или вычтены, а порядок не является применимой концепцией … что приносит нас к Watchcollection.

$ watchcollection – тип 3

Этот тип часов предназначен для массивов JavaScript, вызывая обратный вызов при возникновении изменений уровня коллекции.

$scope.firstTeam = [{
  first: 'steph',
  last: 'curry'
}, {
  first: 'lebron',
  last: 'james'
}];
$scope.$watchCollection('firstTeam', function(firstTeamArray) {
  console.log("change to the first team! ", JSON.stringify(firstTeamArray));
});

$timeout(function() {
  $scope.firstTeam.push({first: 'russel', last: 'westbrook'});
}); // new member, print!

$timeout(function() {
  $scope.firstTeam.sort(function(player1, player2) {
    if (player1.first < player2.first) return -1;
  });
}, 300); // reordering, print!

$timeout(function() {
  $scope.firstTeam[0].height = 75;
}, 600); // member mutation, no print

Преимущества и ограничения WatchCoLlectionwhere WatchGroup Mouse позволяет нескольким выражениям, способным контекстуальную оценку, чтобы указать на один обратный вызов, Watchcollection обеспечивает только один – в приведенном выше примере «firstTeam». С другой стороны, тип часов, применяемых к такому выражению, более вовлечен. Наблюдатели типа 1 уход только о адресах для объектов и значений для примитивов. Как сами объекты, массивы ничем не отличаются. В зависимости от часов типа 1, выражения, которые оценивают на массив, не будут регистрировать изменения, независимо от того, насколько мутированы между четками, пока не выключится для совершенно нового массива и адреса в памяти. Watchcollection значительно отличается. Мутация – это имя игры. В частности, Watchcollection держит взгляд на два типа мутаций массива уровня поверхности: (1) Добавление/вычитание и (2) переупорядочение. Добавление или вычитание членов массива и переупорядочения членов массива приводит к распознаванию изменений и зарегистрированным обратным вызовам. Watchcollection останавливается только в том числе просмотра мутации ниже поверхности I.e. Глубокая мутация, мутации самим участникам … что приносит нам глубокие просмотр.

$ watch (…, …, true) – Тип 4

Наиболее дорогими часами, этот тип часов также является самым тщательным, рекурсивно масштабирующим глубины любого сложного объекта и вызывая зарегистрированный обратный вызов, когда любая ветвь дерева претерпела изменения. Обратите внимание на истинный флаг, который сообщает угловой, чтобы выполнить этот тип часов вместо типа 1:

scope.tree = {
  type: 'oak',
  branches: [{
    color: 'brown',
    length: '11',
    leaves: [{
      color: 'green',
      shape: 'oval',
    }, {
      color: 'brown',
      shape: 'leafy'
    }]
  }]
};
scope.$watch('tree', function(tree) {
  console.log('change to tree!', JSON.stringfiy(tree));
}, true);

$timeout(function() { scope.tree.type = 'sequoia'; }); // mutation, print!

$timeout(function() {
  scope.tree.branches[0].length = 12; // mutation, print!
}, 100);

$timeout(function() {
  scope.tree.branches[0].leaves[0].color = 'clementine'; // mutation, print!
}, 200);

$timeout(function() {
  scope.tree.branches[0].leaves.push({ // mutation, print!
    color: 'rosemary'
  });
}, 300);

$timeout(function() {
  scope.tree = 'hello!'; // mutation, print!
}, 400);

Смотреть (…, …, true) не имеет ограничений, наблюдая не имеет ограничений, кроме работы, кроме работы, – последнее, что ваши потребности в приложении являются рекурсивными поездками на глубины сложных объектов каждый цикл дайджета. С другой стороны, глубокие наблюдения могут сохранять какие-либо сложные данные в синхронизации с видом и, в результате, могут быть самым простым для понимания: все изменения изменяются.

Это было обсуждение многих слоев данных, наблюдая в Angularjs. Я надеюсь, что это поможет сообщить вашему выбору среди них!