Подтвердить что ты не робот

Создание копий больших списков для запуска обнаружения изменений для чистых каналов в Angular 2, влияющих на производительность

У меня есть массив a, содержащий 50 000+ объектов, и у меня есть канал, который принимает этот массив a и преобразует его в некоторый вывод, который затем отображается в представлении.

Труба имеет чистое значение, так как только при изменении ссылки на массив a она будет переоцениваться.

У меня есть метод modifyArray, который добавляет/удаляет некоторые элементы из массива a. По завершении я хотел бы, чтобы труба была переоценена так, чтобы представление повторно отображалось.

Из-за того, что Angular обеспечивает неизменность, единственный параметр, который у меня есть для перепрограммируемого канала, заключается в том, что метод modifyArray возвращает копию массива a с внесенными изменениями, так что Angular может обнаружить, что ссылка изменилась и вызывать канал, что-то вроде этого:

modifyArray(a: T[]): T[] {

  a.push(b);
  a.slice(c);

  return [...a];
}

Однако для такого массива с 50 000 + элементами при создании копии массива происходит реальное снижение производительности.

Я бы предположил, что явное инициирование обнаружения изменений после вызова этого метода, например, путем вызова ApplicationRef.tick() или ChangeDetectorRef.detectChanges(), позволит Angular понять, что массив был изменен, но это не случай:

this.a = modifyArray(a);

this.applicationRef.tick();

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

Есть ли у кого-нибудь идеи о том, как это можно достичь?

4b9b3361

Ответ 1

Angular2 Обнаружение изменений только проверяет ссылки на объекты. Он не зависит от того, как часто он проверяет, а только то, что он не смотрит внутрь массивов;-), поэтому явное обращение к обнаружению изменений не имеет никакого эффекта.

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

Вы можете использовать директиву *ngFor в качестве примера https://github.com/angular/angular/blob/14ee75924b6ae770115f7f260d720efa8bfb576a/modules/%40angular/common/src/directives/ng_for.ts#L122

Ответ 2

Я не уверен в вашей ситуации, но, как правило, отображение 50 000 элементов - не лучшая идея, так как ни один человек не сможет ничего сделать с таким массивным массивом. Итак, первое, что вы можете попытаться сделать, это обработать больше данных на сервере и вернуть часть, которая действительно нужна (например, первые 20 записей, отфильтрованных некоторым полем поиска).

Если это почему-то не работает для вас (хотя интересно узнать, почему нет), вы можете просто попробовать обработать свой массив самостоятельно и запомнить результат в переменной на компоненте. Команда Angular2 сделала решение, чтобы не включать трубку filter или sorting из-за проблемы с производительностью. Их рекомендации - хранить данные, необходимые вам самим. То есть когда вы получите массив (или обновите позже), обработайте его и сохраните результат в отдельной переменной, доступной для html через компонент.

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

Ответ 3

ваш массив изменен, и ваш канал не переоценивается, это ограничение чистого канала.. Здесь чистый выбор ошибки здесь.

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

Решение: Нечистая труба. Эта труба будет слушать все события и перезапускать трубку для вас. эта труба может быть недостатком в вашем случае bcz у вас есть большой объем данных в массиве, это может вызвать проблемы с производительностью, но это сработает для вас.

Как создать нечистую трубу: просто добавьте pure:false в оформление трубы.

 @Pipe({
        name: 'my-custom-pipe',
        pure: false
     })