Как свести слушателей Angular 6 JS к минимуму с +4000-5000 полей формы

Работаю над приложением для составления отчетов о расписании для ресурсов сайта. Для разных местоположений может быть более 500-600 позиций, каждая строка имеет не менее 16 полей формы, хотя только 8 имеют «назначенный» компонент HTML.

общий вид формы выглядит следующим образом: введите здесь описание изображения Каждая позиция – это отдельный компонент формы в FormArray, который является частью родительской формы. Сама форма «управляется» службой форм, которая обрабатывает большую часть извлечения данных, а также добавления и удаления элементов строки.

Генерация FormArry выполняется в formService

//Initiate listener on service
this.service.getDate.subscribe((data: IInterface[]) => {
      data.map(lineitem => {
          const array = this.getFormArray(lineitem.group);
          lineitem.id = array.length + 1;
          let iform = this.fb.group(new LineItemForm(lineitem));
          array.push(iform);
      });
  });

Ini для данных запускается одним вызовом из родительской формы по нажатию кнопки, вышеприведенный слушатель распределяет данные по 4 отдельным массивам с помощью lineitem.group. Что все работает как положено.

В родительской форме HTML формы элементов строки генерируются следующим образом, а Array происходит из formService, где он фильтруется по номеру страницы в статический массив (т. е. службе не нужно вызывать или фильтровать при извлечении массива в родительском поскольку это уже было сделано при извлечении данных, поэтому Array должен быть «готов к работе»)

<lineitem *ngFor="let lineitem of Array?.controls; let i = index"
              [index]="i"
              [LineItemForm]="lineitem"
              (deleteLineItem)="deleteLineItem($event)">
 </lineitem>

компонент lineitem-form имеет следующие спецификации и свойства.

После рендеринга представления строки каждая форма строки отделяется от процесса ChangeDetection, и все подписки помещаются в массив, чтобы мы могли отписаться от всех после ngOnDestroy. На данный момент инициировано только 3 слушателя подписки. (1 для типа сотрудника, один для массива сотрудников (который поступает из службы и один для массива ресурсов (также из службы))

@Component({
    selector: 'lineitem',
    templateUrl: './lineitem.component.html',
    styleUrls: ['./lineitem.component.css', './../form.component.css'],
    changeDetection: ChangeDetectionStrategy.OnPush
 })

constructor(
    private formService: formService,
    private modalService: BsModalService,
    private cd: ChangeDetectorRef
) {        
}

ngAfterViewInit() {
    this.cd.detach();
}

ngOnDestroy() {
    this.subscriptions.forEach(c => c.unsubscribe());
}

Поля с понедельника по воскресенье имеют (change) привязку к методу расчета в компоненте формы, в конце метода ChangeDetectionRef запускается для запуска this.cd.detectChanges() для обновления каждой отдельной строки-формы.

calculateThings(){

    // … do some calculations and form-field sets

    //Trigger change detection cycle
    this.cd.detectChanges();
}

Родительская форма установлена ​​на ChangeDetection.Default (хотя переключение на OnPush не уменьшает количество слушателей)

Чтобы решить (частично) проблему, я разделил общее количество элементов строки на вкладках, каждая вкладка генерируется только при фактическом отображении с использованием привязки *ngIf. Это уменьшает количество слушателей примерно до 2000-4000 на активной вкладке. Однако, если пользователь щелкает туда-сюда между двумя вкладками, слушатели снова быстро начинают складываться.

На каком-то этапе — хотя и нерегулярно и без ясной «причины» — количество слушателей снова сбрасывается до более управляемых 2000-3000 (все еще много, но это работает). Я могу отобразить около 35-50 строк (т. заметна задержка во времени отклика.

Это приводит к нескольким вопросам:

  1. Есть ли способ «очистить» слушателей при переходе с вкладки на вкладку (т.е. при повторном создании DOM)
  2. Есть ли способ «сбросить» DOM, чтобы количество слушателей упало почти до нуля
  3. Каков наилучший (или рекомендуемый) способ обработки этого количества строк/поля формы (если я посмотрю, например, на ag-Grid, они, похоже, смогут генерировать 10000 строк при 100 столбцах, не превышая 2000 слушателей?? ?, правда, без вычисления полей, насколько я вижу)
  4. Единственный способ контролировать количество слушателей, ограничивая фактическое количество полей формы в активном DOM?

Я был бы признателен за любые подсказки и советы, которые могли бы предоставить некоторую дополнительную информацию.

В текущем решении я разделяю массив форм на вкладки и разбиваю на страницы массивы на каждой вкладке, содержащие более 50 строк. Это работает, но мне любопытно, есть ли «более чистые» решения?

PS: Я был бы признателен, если бы мы могли избежать комментариев, например, зачем вам вообще нужно столько полей формы. Что, хотя и является закономерным вопросом, не помогает, поскольку это критерий дизайна для развертывания его среди пользователей. Если у вас есть конструктивная информация о том, как ввести 7 дневных значений для 600 ресурсов в 1 форму, тогда я весь слушаю?


person mtholen    schedule 06.12.2019    source источник
comment
Вы можете рассмотреть возможность использования одного делегированного прослушивателя событий, который обрабатывает несколько элементов.   -  person James    schedule 06.12.2019
comment
@James Звучит интересно, не могли бы вы предоставить ссылку на дополнительную справочную информацию о том, как это реализовать?   -  person mtholen    schedule 06.12.2019
comment
Что вы используете в настоящее время для привязки массива данных в шаблоне - FormBuilder/Reactive form или Template-driven/[(ngModel)]? Кроме того, вы используете ChangeDetectionStrategy.OnPush?   -  person Krishnan    schedule 06.12.2019
comment
При использовании Reactive Forms, ChangeDetectionStrategy.OnPush, каждая форма элемента строки отсоединяется от ChangeDetectionRef, а метод detectChanges() запускается вручную после одного вызова метода в элементе строки. Таким образом, количество слушателей, которые фактически инициируются в форме, сведено к минимуму. Но эта стратегия, похоже, не уменьшает фактических слушателей JS (как показано в окне разработчика Chrome).   -  person mtholen    schedule 06.12.2019
comment
Angular на самом деле не моя тема, поэтому я могу только догадываться о ссылках на ссылку. Я бы просто погуглил делегирование событий angular. вот один   -  person James    schedule 06.12.2019
comment
Хорошо, это хорошие стратегии, которые вы используете. Я вижу, что вы обновляете свой вопрос. Возможно, я не смогу ответить на этот вопрос, но я думаю, что другим будет полезно визуализировать это, если вы добавите несколько фрагментов кода своих компонентов и шаблонов.   -  person Krishnan    schedule 06.12.2019
comment
@Krishnan Я обновлю завтра фрагментами кода.   -  person mtholen    schedule 06.12.2019


Ответы (1)


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

Здесь используется новая опция под названием ngZoneEventCoalescing.

«Сокращение циклов обнаружения изменений с объединением событий в Angular», Нетанель Базал https://link.medium.com/jG2bFqx3j2< /а>

person Krishnan    schedule 11.12.2019
comment
Большое спасибо, посмотрю. Я кратко рассмотрел зонирование, но не реализовал что-то подобное, в конце концов, это может быть решением. Тем временем я смог настроить параметры службы и вставить поля формы только тогда, когда они относятся к строке. Это сократило количество слушателей примерно до 2000-3000, отображая при этом около 50 строк ресурсов. - person mtholen; 11.12.2019
comment
Прохладно. Надеюсь, поможет. - person Krishnan; 11.12.2019