3 cara membuat daftar besar di Angular

Pada tahun 2020, kerangka kerja front-end menjadi lebih baik, lebih efisien dan lebih cepat. Tetapi, bahkan dengan mengingat hal ini, membuat daftar besar tanpa "pembekuan" browser masih bisa menjadi tugas yang menakutkan bahkan untuk kerangka kerja tercepat yang ada.

Ini adalah salah satu kasus di mana "kerangka kerjanya cepat dan kodenya lambat." Ada banyak pendekatan yang memungkinkan Anda untuk menampilkan sejumlah besar elemen tanpa memblokir interaksi pengguna dengan halaman web. Penulis artikel, terjemahan yang kami terbitkan hari ini, ingin menjelajahi metode yang ada untuk menampilkan daftar besar di halaman web dan berbicara tentang bidang aplikasi mereka.







Meskipun materi ini ditujukan untuk Angular, apa yang dibahas di sini berlaku untuk kerangka kerja dan proyek lain yang ditulis dalam JavaScript murni. Secara khusus, pendekatan berikut untuk merender daftar besar akan dipertimbangkan di sini:

  • Pengguliran virtual (menggunakan CDK Angular).
  • Render manual.
  • Render progresif.

Pengguliran virtual


Pengguliran virtual mungkin merupakan cara paling efisien untuk bekerja dengan daftar besar. Benar, dia memiliki beberapa kelemahan. Pengguliran virtual, terima kasih kepada Angular CDK dan plugin lainnya, sangat mudah diimplementasikan dalam komponen apa pun.

Gagasan di balik pengguliran virtual itu sederhana, tetapi tidak selalu mudah diimplementasikan. Intinya di sini adalah bahwa kita memiliki wadah dan daftar elemen. Elemen diberikan hanya jika berada di dalam area wadah yang terlihat.

Kami akan menggunakan modul scrollingdari CDK Angular, yang dirancang untuk mengatur pengguliran virtual. Untuk melakukan ini, Anda harus menginstal CDK terlebih dahulu:

npm i @angular/cdk

Maka Anda perlu mengimpor modul:

import { ScrollingModule } from '@angular/cdk/scrolling';
@NgModule({
 ...
 imports: [ ScrollingModule, ...]
})
export class AppModule {}

Setelah itu, komponen dapat digunakan cdk-virtual-scroll-viewport:

<cdk-virtual-scroll-viewport itemSize="50">
 <div *cdkVirtualFor="let item of items">
   {{ item }}
 </div>
</cdk-virtual-scroll-viewport>

Berikut adalah contoh proyek yang menggunakan pendekatan ini untuk mengatur pengguliran virtual.

Seperti yang Anda lihat, mekanisme Angular standar memungkinkan Anda mencapai hasil yang mengesankan tanpa banyak kesulitan. Komponen dalam contoh membuat ribuan elemen tanpa masalah.

Jika pengguliran virtual sangat bagus, dan jika sangat mudah diterapkan, muncul pertanyaan mengapa mempelajari cara lain untuk membuat daftar besar. Saya juga tertarik dengan pertanyaan ini. Ternyata, keadaan ini memiliki beberapa alasan:

  • , , . , . , Autocomplete ( ). , , , , . — .
  • — , .
  • Ada beberapa masalah dengan aksesibilitas dan kemudahan penggunaan isi daftar dengan pengguliran virtual. Elemen tersembunyi tidak dirender - ini berarti bahwa mereka tidak akan tersedia untuk pembaca layar, dan bahwa mereka tidak dapat ditemukan pada halaman menggunakan mekanisme browser standar.

Pengguliran virtual sangat ideal dalam sejumlah situasi (asalkan berfungsi):

  • Dalam hal itu, jika Anda ingin menampilkan daftar yang ukurannya tidak diketahui sebelumnya, atau yang bisa sangat besar (menurut perkiraan kasar, daftar yang mencakup lebih dari 5 ribu elemen, tetapi ini sangat tergantung pada kompleksitas setiap elemen).
  • Jika Anda perlu mengatur pengguliran tanpa akhir.

Render manual


Salah satu cara untuk bekerja dengan daftar yang saya coba untuk mempercepat keluaran dari sejumlah besar elemen adalah dengan menggunakan rendering manual menggunakan Angular API *ngFor.

Kami memiliki template sederhana yang menggunakan loop yang diatur menggunakan direktif *ngFor

<tr 
*ngFor="let item of data; trackBy: trackById; let isEven = even; let isOdd = odd"
    class="h-12"
    [class.bg-gray-400]="isEven"
    [class.bg-gray-500]="isOdd"
>
  <td>
    <span class="py-2 px-4">{{ item.id }}</span>
  </td>

  <td>
    <span>{{ item.label }}</span>
  </td>

  <td>
    <a>
      <button class="py-2 px-4 rounded (click)="remove(item)">x</button>
    </a>
  </td>
</tr>

Untuk mengukur kinerja rendering 10.000 elemen sederhana, saya menggunakan tolok ukur berdasarkan js-frameworks-benchmark .

Pertama, saya memeriksa kinerja daftar, yang menggunakan loop reguler ke output *ngFor. Akibatnya, ternyata scripting mengambil 1099 ms., Render (Rendering) mengambil 1553 ms., Dan lukisan (Lukisan) - 3 ms.


Sebuah studi tentang kinerja daftar, yang menggunakan * ngFor untuk menghasilkan,

item Daftar dapat dirender secara manual menggunakan API Angular:

<tbody>
  <ng-container #itemsContainer></ng-container>
</tbody>
<ng-template #item let-item="item" let-isEven="isEven">
  <tr class="h-12 "
      [class.bg-gray-400]="isEven"
      [class.bg-gray-500]="!isEven"
  >
    <td>
      <span class="py-2 px-4">{{ item.id }}</span>
    </td>

    <td>
      <span>{{ item.label }}</span>
    </td>

    <td>
      <a>
        <button class="py-2 px-4 rounded" (click)="remove(item)">x</button>
      </a>
    </td>
  </tr>
</ng-template>

Mari kita bicara tentang bagaimana kode pengontrol telah berubah.

Kami mendeklarasikan templat dan wadah:

@ViewChild('itemsContainer', { read: ViewContainerRef }) container: ViewContainerRef;
@ViewChild('item', { read: TemplateRef }) template: TemplateRef<any>;

Saat menghasilkan data, kami membuatnya menggunakan metode createEmbeddedViewentitas ViewContainerRef:

private buildData(length: number) {
  const start = this.data.length;
  const end = start + length;

  for (let n = start; n <= end; n++) {
    this.container.createEmbeddedView(this.template, {
      item: {
        id: n,
        label: Math.random()
      },
      isEven: n % 2 === 0
    });
  }
}

Akibatnya, indikator yang mencirikan kinerja daftar sedikit meningkat. Yaitu, butuh 734 ms untuk mengeksekusi kode, 1443 ms untuk merender, 2 ms untuk menggambar.


Meneliti kinerja daftar yang menggunakan API Angular untuk menghasilkan

True, dalam praktiknya, ini berarti bahwa daftar tersebut masih sangat lambat. Ketika Anda mengklik tombol yang sesuai, browser "membeku" selama beberapa detik. Jika ini muncul dalam produksi, pengguna pasti tidak akan menyukainya.

Begini tampilannya (di sini saya, menggunakan mouse, meniru indikator memuat).


Daftar Memperlambat

Sekarang, untuk meningkatkan rendering daftar manual, kami akan mencoba menerapkan teknologi rendering progresif.

Render progresif


Gagasan rendering progresif sederhana. Ini terdiri dalam rendering subset elemen secara progresif, menunda rendering elemen lain dalam loop peristiwa. Ini memungkinkan browser untuk menampilkan semua elemen tanpa "melambat".

Kode di bawah ini yang menerapkan render daftar progresif sangat mudah:

  • Pertama, menggunakan ini setInterval, kami membuat biasa, setiap 10 ms. Panggil ke fungsi yang membuat 500 elemen saat dipanggil.
  • Setelah semua elemen disimpulkan, yang kami tentukan berdasarkan analisis indeks elemen saat ini, kami menghentikan pemanggilan fungsi reguler dan mengganggu siklus.

private buildData(length: number) {
  const ITEMS_RENDERED_AT_ONCE = 500;
  const INTERVAL_IN_MS = 10;

  let currentIndex = 0;

  const interval = setInterval(() => {
    const nextIndex = currentIndex + ITEMS_RENDERED_AT_ONCE;

    for (let n = currentIndex; n <= nextIndex ; n++) {
      if (n >= length) {
        clearInterval(interval);
        break;
      }
      const context = {
        item: {
          id: n,
          label: Math.random()
        },
        isEven: n % 2 === 0
      };
      this.container.createEmbeddedView(this.template, context);
    }

    currentIndex += ITEMS_RENDERED_AT_ONCE;
  }, INTERVAL_IN_MS);

Harap dicatat bahwa jumlah elemen yang ditampilkan per panggilan ke fungsi yang ditransfer setInterval, serta frekuensi panggilan ke fungsi ini, sepenuhnya tergantung pada keadaan. Misalnya, jika elemen-elemen dari daftar yang ditampilkan sangat kompleks, maka output dari 500 elemen tersebut dalam sekali jalan akan sangat lambat.

Dengan mengukur kinerja solusi ini, saya mendapatkan hasil yang terlihat lebih buruk daripada yang saya terima sebelumnya. Eksekusi kode - 907 ms., Rendering - 2555 ms., Menggambar - 16 ms.


Meneliti kinerja daftar, yang hasilnya menggunakan render progresif.Tapi

pengguna, yang bekerja dengan daftar seperti itu, akan mengalami pengalaman yang jauh lebih menyenangkan daripada sebelumnya. Meskipun waktu yang diperlukan untuk membuat daftar meningkat, pengguna tidak akan melihatnya. Kami, dalam sekali jalan, membuat 500 elemen. Dalam hal ini, rendering dilakukan di luar batas wadah.

Di sini, beberapa masalah mungkin timbul karena kenyataan bahwa wadah berubah ukuran selama rendering, atau posisi bergulir konten berubah. Jika ini terjadi, Anda harus menghadapi masalah serupa.

Inilah yang bekerja dengan daftar seperti itu.


Daftar cepat

Ringkasan


Teknik render manual dan progresif untuk daftar besar tentu berguna dalam beberapa situasi. Saya menggunakannya dalam kasus di mana pengguliran virtual untuk beberapa alasan tidak cocok untuk saya.

Mengingat hal di atas, kita dapat mengatakan bahwa paling sering pengguliran virtual, dibangun berdasarkan perpustakaan yang baik, seperti CDK Angular, adalah cara terbaik untuk menampilkan daftar besar. Tetapi jika karena alasan tertentu pengguliran virtual tidak dapat digunakan, pengembang memiliki kemungkinan lain.

Pembaca yang budiman! Bagaimana Anda menampilkan daftar besar di proyek web Anda?


All Articles