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

Оптимизация обнаружения изменения в угловой 2+ на примере

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

Автор оригинала: Kevin Farst.

Одна из вещей, по умолчанию, по умолчанию имеет автоматическое обнаружение изменений, что означает, что когда свойство объекта или объекта изменяется при выполнении во время выполнения, изменение будет отражено в представлении без необходимости настроить любой механизм ручного механизма для этого. В версии 2 и выше, угловые попытались расширить возможности разработчикам больше контроля над тем, как и когда проверять изменения. Я демонстрирую это в примере из класса, который я преподавал в Интернете, который я хотел бы поделиться, в надежде, что он даст вам больше конкретного понимания этой идеи.

Обнаружение изменения в угловой 1

Во-первых, давайте посмотрим, как Angular 1 выполнил то же самое. Для каждого выражения в приложении наблюдателю будут назначаться при регистрации на $ Scope Затем каждый раз произошел изменения, угловые будут проходить через список каждый Наблюдатель, чтобы убедиться, что значение, возвращенное из выражения, не изменилось. Это было описано как Цикл Digest А для каждого изменения, найденного в списке, еще один цикл дайджесте будет работать до тех пор, пока он не успешно пройдет через список, не имею никаких изменений. Этот подход имеет несколько недостаток, однако:

  • Если выражение имеет изменяющее значение каждый цикл Diagest, например, если вы случайно создали новый объект каждый раз, когда выражение было оценено, вы в конечном итоге получите все слишком знакомые ошибки:
10 $digest() iterations reached. Aborting!

Угловой будет выбросить ошибку, после 10 циклов Diagest, чтобы предотвратить бесконечную петлю.

  • Более актуально к этому посту, нет гарантированного постановления, к которому бегите наблюдатели, поэтому вы потенциально можете столкнуться с ситуацией, когда обнаружение изменения в дочернем режиме/компонент будет нарастаться до его родитель, ведущий к некоторым странным результатам. В визуальной древесной структуре обнаружение изменений может в конечном итоге охватывать каждый узел, как так:
Pgcqycv.png.

Счастливые деревья

Bobross1.jpg.

Поскольку угловые 2+, приложения по определению, построенному со структурой вложенного дерева, начиная с корневого компонента. Следовательно, не более потенциально для дилеммы «куриного или яйца» с точки зрения обнаружения изменений между родительными/дочерними компонентами.

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

6giapza.png.

Звучит отлично, в чем проблема?

Направленный график дерева делает вещи намного быстрее, и это встроенное поведение обычно будет единственным, что вам понадобится в вашем приложении Angular 2+. Однако, поскольку в центре внимания этого поста будет оптимизация, наш вопрос будет: что происходит, когда узел (вложенный компонент) дальше вниз по дереву регистрирует изменение?

R26Z31H.png.

Как упомянуто выше, угловая всегда будет проходить каждый экземпляр компонента один раз, начиная с корня. Кроме того, поскольку JavaScript не обладает возмезмой объекта, угловой должен быть консервативным и проверять, чтобы убедиться, что каждый экземпляр компонента не изменился, поскольку обнаружение изменений было последним запуском.

Fs2gvdb.png.

Что, если мы только хотим запустить обнаружение изменения при определенных обстоятельствах? Существует на самом деле несколько способов сделать это, но мы охватим наиболее простого ниже.

Обучение по примеру

Давайте посмотрим на небольшое примерное приложение, которое перечислены фильмы разных категорий (новые, предстоящие, топ-рейтинг и т. Д.). Moviedetailscomponent берет @Input () объект для представления фильм Список мы хотим детали для.

import {
  Component,
  Input,
  ...
} from '@angular/core';

@Component({
  selector: 'movie-details',
  ...
})
export class MovieDetailsComponent {
  @Input('movie') movieData: Movie;
  ...
}


Фильм Тип – это интерфейс с номерами, связанными с фильмом, а также флаг, помеченный отмечено Отказ

export interface Movie {
  id: number;
  title: string;
  release_date: string;
  overview: string;
  ...
  markedToSee: boolean;
}

Давайте псевдоним фильм объект к переменной Moviedata внутри Moviedetailscomponent Таким образом, мы можем «зацепить» фильм Объект вызывается и вставьте оператор для входа в консоль. ES6 позволяет нам использовать получить Синтаксис для «связывать свойство объекта к функции, которая будет вызвана, когда вызывается имущество».

import {
  Component,
  Input,
  ...
} from '@angular/core';

@Component({
  selector: 'movie-details',
  ...
})
export class MovieDetailsComponent {
  @Input('movie') movieData: Movie;

  get movie() {
    console.log(`GET movie: ${this.movieData.title}`);
    return this.movieData;
  }
  ...
}

В нашем списке фильмов у нас есть ссылка на топ, что при нажатии случайно выберете фильм для нас. Это будет отмечено некоторым текстом и фоном подсветки цвета. Кроме того, мы можем видеть, как выяснение изменений на каждый Moviedetailscomponent экземпляр, когда Marktosee Флаг перевернут «только один фильм».

Функция события, привязанная к этому действию, выглядит так:

  // In parent component
  pickMovie(event: any) {
    event.preventDefault();
    let movie: Movie = this.movies.find(movie => movie.markedToSee);
    // If a movie was already marked to see, set the flag back to false
    if (movie) {
      movie.markedToSee = false;
    }
    // Mark a random movie to see, mark the flag as true
    this.movies[Math.floor(Math.random() * this.movies.length)].markedToSee = true;
  }

И тестирование его в браузере …

Lbvglbe.gif.

Мы видим, что оба раза мы нажали Выбрать случайный фильм, чтобы увидеть это называется функцией Getter для фильм объект каждый Moviedetailscomponent Отказ Он также называл Getter несколько раз для каждого привязки свойства в представлении (заголовок, обзор и т. Д.), Но это только сбоку. В идеале мы хотим видеть только функцию Getter, вызванную один или два компонента (один, если это первый раз, когда мы выбираем фильм, чтобы увидеть, два, если мы снова нажали его, и majorttosee Флаг был выключен для старого фильма и перевернулся на новый фильм).

Принимать изменение обнаружения в наших собственных руках (вроде)

Мы можем сказать, что угловалось быть более агрессивным о решении, когда использовать обнаружение изменения, изменяя CENSEDETICEGRATEGY Отказ Мы используем значение по умолчанию прямо сейчас, что всегда будет проверять обновления на компонент – если мы явно помемте его как Onpush , он будет запущен только изменение обнаружения, когда:

  • Ссылка на @Input () Объект изменен
  • Событие срабатывает внутри компонента
import {
  Component,
  Input,
  ChangeDetectionStrategy,
  ...
} from '@angular/core';

@Component({
  selector: 'movie-details',
  changeDetection: ChangeDetectionStrategy.OnPush,
  ...
})

ОНО СЛОМАЛОСЬ!!!!!!!

А.Гиф.

Конечно, если вы снова пойдете и проверяете в браузере, вы увидите, что «выбрать случайный фильм, чтобы увидеть» – это Borken – он больше не выбирает для нас фильма, и мы не видим операторы регистратора в консоли, который является еще одной проверкой. отмечено это недвижимость на фильм объект и фильм Объект – это @Input () Собственность, поэтому объект «изменился» верно?

Ну да и нет. Само объект изменился, но Ссылка Для объекта не изменилось, это тот же объект. Как упомянуто выше, обнаружение изменения произойдет только в том случае, если ссылки на объект изменяется. Как мы можем настроить это, чтобы мы получим результаты, которые мы хотим?

Легкий способ – посмотреть на отмечено сама недвижимость. Эта логика на самом деле не принадлежит Фильм Тип, как это относится к просмотру логики и для пользовательской логики, так что, если мы перевели его в отдельный @Input () Недвижимость на Moviedetailscomponent (Поскольку это ответственность родительского компонента за обновление этого флага в любом случае)?

Сначала компонент …

  ...
  export class MovieDetailsComponent {
    @Input('movie') movieData: Movie;
    @Input() markedToSee: boolean;
    ...
  }

Затем тег HTML …

  
  

И, наконец, функция обновления отмечено кино…

// In parent component
...
export class MoviesComponent {
  selectedMovieIndex: number;

  pickMovie(event: any) {
    event.preventDefault();
    this.selectedMovieIndex = Math.floor(Math.random() * this.movies.length);
  }
}

Успех!

B.GIF.

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

Также, если наше Moviedetailscomponent Удаленные компоненты в нем в качестве дочерних компонентов мы могли бы гипотетически пропустить целые субтреевые элементы при обнаружении изменения с помощью CENSEDETIONSTRATEGY.ONPUSH Отказ

y3mafmd.png.png

дальнейшее чтение

Наконец, как я уже упоминал ранее, есть несколько способов принять больше контроля над обнаружением изменений угловых углов, и мы охватывали один из них. Для большего контроля над индивидуальным механизмом обнаружения изменений в экземпляре компонента проверяйте документацию для СЛЕДУЮЩИЙРЫРЕФ Отказ

Заключение

Угловые 2 и выше дают нам больший контроль над обнаружением изменения, чем у нас когда-либо с угловой экосистемой. Действительно является крупным усилением просто проходить через огромный список наблюдателей каждый раз, когда сделано изменение. Хотя механизм по умолчанию уже быстро быстро, мы можем в дальнейшем настроить наш механизм обнаружения изменений, когда он нужен. Примером, который я использовал, оставляет много кода для этой статьи, но вы можете найти полный исходный код как часть онлайн-углового уровня 2+ класса, которого я преподавал здесь Отказ

Счастливое кодирование! 😃.

Этот пост был первоначально опубликован автором здесь Отказ Эта версия была отредактирована для ясности и может появиться отличаться от исходного поста.