Angular 7 - загрузка данных кусками замедляет страницу - PullRequest
0 голосов
/ 06 декабря 2018

Сводка

Как правильно использовать Angular 7 для загрузки списка, а затем выполнить итерацию по этому списку, делая вызовы http для заполнения дополнительных данных?

Подробности

Я использую Angular 7 на сервере Node.JS.

Мне нужно отобразить список элементов.Я могу получить основные детали, скажем, название и изображение предмета, очень быстро.Тем не менее, некоторые детали требуют некоторого времени для вычисления на бэкэнде - скажем, сколько раз оно было куплено и состояние, которое приобрело большую часть предмета.

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

Итак, у меня есть 2 API.

  1. Возвращает список из 200+элементы с их названием, ценой и изображением (ответы в ~ 500 мс).
  2. При наличии списка идентификаторов, вернуть комплексную информацию для элемента (~ 250 мс-2000 мс).

Вот псевдокод того, что я сделал:

public ngOnInit() {
   this.service.getList().subscribe(list => {
      this.items = list;
      list.forEach(i => pendingIds.push(i.id));
      this.loadDetails();
   });
}

public pendingIds = [];    
public loadDetails() {
   ids = this.pendingIds.popAFew();
   this.service.getDetails(ids).subscribe(info => {
      this.items[id].properties = info.properties;
      if (pendingIds.length) {
         this.loadDetails();
      }
   });
}

Приведенный выше код "работает", но страница дрожит / не очень отзывчива, пока все данные не заканчивают загружаться.

Если я уберу вызов loadDetails (), то страница загружается быстро и мгновенно реагирует.

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

Я играл с асинхронным каналом и 'rxjs / observable / from', но я не нашел секретсоус.

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

Редактировать

Я пытался использовать flatMap, см.следующий, но все еще нервный:

public pendingIds = [];    
public loadDetails() {
   let obs: Observable<any>;
   this.pendingIds.forEach(id => {
      if (!obs) {
         obs = this.service.getDetails(id).pipe(tap((info) => this.loadDetails(info)));
      } else {
         obs = obs.pipe(
            flatMap(() => this.service.getDetails(id)),
            tap((infp) => this.loadDetails(info))
         );
      }
   });
   obs.subscribe(() => {{);
}

Редактировать 2

3-й способ загрузки - все еще нервный.

let activeRequests = 0;
Observable.create((observer) => {
    const interval = setInterval(() => {
        if (activeRequests < 2) {
            if (this.pendinIds.length > 0) {
                observer.next(this.pendingIds.shift());
            } else {
                clearInterval(interval)
            }
        }
    }, 25);
    return () => clearInterval(interval);
})
.pipe(flatMap(id => { activeRequests++; return this.service.getDetails(id); })
.subscribe(info => { --activeRequests; this.loadDetais(info})

Любойидеи?

1 Ответ

0 голосов
/ 01 февраля 2019

Я решил замедление, используя обнаружение изменений OnPush.

Краткий ответ: начните с ваших конечных компонентов и:

  • Добавьте changeDetection: ChangeDetectionStrategy.OnPush к объявлению компонента.
  • Добавьте private ChangeDetector: ChangeDetectorRef в конструктор компонента.
  • Вызовите this.ChangeDetector.markForCheck(); везде, где ваши данные изменяются в компоненте.

Для полного объяснения см .: https://blog.thoughtram.io/angular/2016/02/22/angular-2-change-detection-explained.html

В любое время вы можете сделать это, используя OnPush - хорошая идея, но это может привести к сложным осложнениям.

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

Я решил эту проблему, создав Subject для родительского элемента, который передается компоненту элемента списка.Затем, когда я получаю дополнительную информацию, я вызываю Subject.next (идентификатор обновленного элемента).Компонент элемента списка подписан на тему, и если его идентификатор совпадает с наблюдаемым идентификатором, он вызывает тот же вызов markForCheck ().

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...