Браузер застревает / зависает при толчке массива под углом 4. Как это исправить? - PullRequest
0 голосов
/ 11 октября 2018

У меня есть массив в logsCompoment.ts с именем logs, и я помещаю новые журналы в этот массив и записываю журналы на html-странице с помощью ngFor.Я делаю это следующими способами.

this.socket.on('newline', (data) => {
                this.logs.push(data);
                }
            });

и в logsCompoment.html я делаю следующее, чтобы показать журналы.

<li *ngFor="let log of logs" [innerHTML]="log"></li>

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

Ответы [ 3 ]

0 голосов
/ 11 октября 2018

Я бы предложил два способа решения этой проблемы.

Один из них - пакетная передача элементов в массив, но это в конечном итоге приведет к зависанию браузера, так как дерево DOM будет быстро расти.

Второйвариант - гораздо лучше реализовать вещь под названием virtual scroll.Это позволит вам просматривать все журналы, но в DOM будет только несколько элементов (тех, которые вы сейчас видите).

См. Эту ссылку для получения дополнительной информации: https://netbasal.com/a-taste-of-angular-material-virtual-scroll-f173c5c70a1

0 голосов
/ 11 октября 2018

Вы можете попробовать использовать rxjs Subject с bufferTime().Это будет поддерживать обновления DOM с постоянной частотой.


Для запроса OP, вот рабочий пример.Я использовал bufferTime() вместо ранее предложенного debounce

Вот рабочий пример в slackbitz .И фрагмент фактического кода:

import { Subject } from 'rxjs';
import { scan, bufferTime } from 'rxjs/operators';
import { interval, Observable } from 'rxjs';

@Component({
  ...
})
export class AppComponent  {
  logs$ = new Subject();
  delayed$: Observable<string[]>;

  constructor () {} 

  ngOnInit() {
    this.delayed$ = this.logs$
    .pipe(
      bufferTime(5000),
      scan((acc: string[], curr: string[]) => [...acc, ...curr], []),
    );

    // stand in code to replace OP's .socket() event listener
    const source = interval(100);
    source.subscribe(num => this.logs$.next(`<p>Log Item ${num}</p>`))
  }
}

Тогда в вашем HTML, вам просто нужно подписаться.например,

<li *ngFor="let log of (delayed$ | async)" [innerHTML]="log"></li>
0 голосов
/ 11 октября 2018

Проблема в том, что манипулирование DOM стоит на самом деле дорого.JavaScript на самом деле достаточно быстрый, чтобы обрабатывать большие массивы, но для каждого нового элемента, добавляемого в DOM, очень высока вероятность того, что страницу нужно выложить с нуля.Поэтому, даже если вы просто добавляете теги <li>, браузер должен оценить все на странице, чтобы определить, должна ли его позиция измениться.

Добавьте тысячу строк в секунду, и теперь есть способ, которым он можетникогда не отставать.

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

...