Prompt dan skenario yang berlaku
Feed aktivitas produk dapat berkembang hingga 100.000 item logis. Cursor API-nya mengembalikan 50 item per permintaan. Sebuah kartu dapat memiliki tinggi 48 hingga 240 piksel setelah teks terbungkus (wraps), gambar dimuat, atau detail diperluas. Pengguna dapat memfilter feed, memperluas kartu, dan menyusun draf balasan inline. Pengguna keyboard dan screen-reader harus dapat berpindah melalui feed tanpa kehilangan fokus atau informasi posisi.
Rancang rentang rendering, pengukuran tinggi variabel, pemuatan inkremental, kepemilikan status (state ownership), scroll anchoring, perilaku fokus, semantik aksesibilitas, dan rencana validasi. Jelaskan kapan daftar sederhana yang dipaginasi atau non-tervirtualisasi menjadi pilihan yang lebih baik.
Jumlah item, ukuran halaman, dan rentang tinggi adalah asumsi wawancara, bukan target produk universal. Pertanyaan ini cocok untuk peran frontend senior, infrastruktur UI, dan performa Web. Keterampilan intinya adalah rendering browser dan desain interaksi, sehingga kategorinya adalah frontend.
Apa yang dievaluasi oleh pewawancara
Pertama, dapatkah kandidat memisahkan empat perhatian yang sering kali tercampur aduk? Paginasi mengontrol rekaman mana yang telah dimuat oleh klien. Virtualisasi mengontrol rekaman yang dimuat mana yang memiliki node DOM. Identitas stabil mengontrol rekaman bisnis mana yang memiliki status (state). Aksesibilitas mengontrol bagaimana DOM parsial mewakili koleksi logis. Satu mekanisme tidak menyelesaikan tiga mekanisme lainnya.
Kedua, dapatkah kandidat menurunkan matematika rentang dari asumsi ukuran baris? Baris dengan tinggi yang sama memungkinkan aritmatika offset langsung. Baris dengan tinggi variabel membutuhkan estimasi, ukuran terukur, offset kumulatif, dan kebijakan koreksi ketika estimasi berubah. Jawaban yang kuat menyebutkan lonjakan scroll yang disebabkan oleh perubahan konten di atas viewport dan mempertahankan anchor logis.
Ketiga, dapatkah kandidat menghindari kerusakan status (state corruption)? Slot visual yang didaur ulang (recycled) bukanlah rekaman bisnis. Draf, seleksi, ekspansi, dan mutasi tertunda membutuhkan ID rekaman yang stabil dan status yang tetap bertahan saat baris di-unmount. Pengurutan, pemfilteran, dan respons halaman yang kedaluwarsa tidak boleh melampirkan data atau status ke indeks yang salah.
Keempat, dapatkah kandidat menjaga aksesibilitas tetap utuh? Hanya me-mount kartu yang terlihat akan menghapus sebagian besar set logis dari DOM. Jawaban yang kuat mempertahankan semantik native atau feed, mengekspos posisi logis dan ukuran set, mengumumkan status sibuk (busy state) dengan benar, menjaga kartu yang difokuskan tetap ter-mount, dan menyediakan jalur pemuatan yang dapat dioperasikan.
Kelima, dapatkah kandidat memvalidasi perilaku alih-alih hanya menjanjikan "scrolling yang mulus"? Jawaban harus mendefinisikan perangkat dan skenario target, lalu mengukur jumlah node yang ter-mount, perilaku frame dan tugas panjang (long-task), pergeseran tata letak (layout shift) atau kesalahan anchor, duplikasi permintaan, memori, retensi fokus, dan output screen-reader.
Pertanyaan untuk diklarifikasi terlebih dahulu
- Apakah daftarnya benar-benar lambat tanpa virtualisasi? Jika produk menampilkan paling banyak beberapa lusin baris sederhana, rendering normal atau paginasi lebih mudah dirawat dan lebih mudah diakses. Ukur sebelum menambahkan windowing.
- Apakah tinggi baris tetap, berbatas, atau arbitrer? Tinggi tetap memungkinkan matematika rentang waktu-konstan. Tinggi variabel memerlukan estimasi dan pengukuran. Embed tak terbatas atau media yang terlambat membuat koreksi scroll lebih sulit dan dapat membenarkan tata letak kartu yang dibatasi.
- Apakah API mengekspos jumlah total atau hanya cursor berikutnya? Total yang diketahui dapat mendukung ukuran set logis penuh. Total yang tidak diketahui mengubah ekspektasi scrollbar dan metadata aksesibilitas. Paginasi cursor juga berarti indeks yang belum dimuat tidak dapat dialamatkan secara langsung.
- Haruskah pengguna melompat ke item arbitrer? Melompat berdasarkan indeks dengan baris variabel yang sebagian besar belum diukur bersifat perkiraan sampai baris terdekat diukur. Melompat berdasarkan ID rekaman mungkin memerlukan pencarian server atau API yang berbeda.
- Status baris mana yang harus bertahan dari unmounting? Hover sementara bisa hilang. Draf balasan, seleksi, ekspansi, kesalahan validasi, dan mutasi optimistik biasanya berada dalam status yang diberi kunci berdasarkan ID rekaman di luar komponen baris.
- Model keyboard dan semantik apa yang berlaku? Feed bacaan, listbox yang dapat dipilih, dan grid yang dapat diedit memiliki peran dan kontrak keyboard yang berbeda. Pilih pola semantik dari interaksi, bukan dari tata letak visual.
- Apa kontrak scroll saat data berubah? Setelah pemfilteran, produk dapat diatur ulang ke atas. Saat item yang lebih lama ditambahkan di awal (prepended), biasanya produk mempertahankan item pertama yang terlihat saat ini. Saat item langsung ditambahkan di akhir (appended), produk hanya mengikuti jika pengguna sudah berada di akhir.
- Apa target penerimaan performa? Sebutkan perangkat target, bentuk data, tindakan scroll, dan anggaran performa. Trace desktop pada baris placeholder kecil tidak memvalidasi feed seluler dengan gambar dan kontrol.
Kerangka jawaban 30 detik
"Saya akan memisahkan pemuatan data, virtualisasi, dan status baris. Cursor loader mengambil dan mendeduplikasi halaman berisi 50 item. Virtualizer hanya merender rentang yang terlihat ditambah overscan kecil dan memposisikan baris-baris tersebut di dalam spacer yang tingginya mewakili data yang dimuat. Baris tetap menggunakan aritmatika offset; baris variabel dimulai dengan estimasi, diukur setelah tata letak, dan memperbarui offset kumulatif. Ketika tinggi sebelum viewport berubah, saya mempertahankan rekaman pertama yang terlihat dan offset intra-barisnya sehingga layar tidak melompat. Setiap baris menggunakan ID rekaman, sementara draf dan seleksi berada di luar baris. Untuk feed aktivitas, saya akan mengekspos semantik feed dan article, posisi logis dan ukuran set, status sibuk, dan tidak pernah meng-unmount kartu yang berisi fokus. Saya akan menguji scroll cepat, perubahan gambar dan ekspansi, race condition filter, perilaku prepend dan append, navigasi keyboard dan screen-reader, jumlah node, long tasks, memori, dan kesalahan anchor. Jika rendering biasa sudah memenuhi anggaran, saya akan mempertahankan daftar yang lebih sederhana."
Penjelasan mendalam langkah demi langkah
Langkah 1: Pisahkan rekaman yang dimuat dari baris yang di-mount
Pertahankan status eksplisit untuk lapisan data: ID rekaman yang berurutan, peta dari ID ke rekaman, cursor berikutnya, status permintaan, dan apakah ada lebih banyak data. Virtualizer menerima ID berurutan yang dimuat dan wadah scroll (scroll container). Ia tidak memiliki cursor, percobaan ulang (retries), draf, atau mutasi server.
Dengan cursor API, awalnya hanya 50 rekaman yang dapat dialamatkan. Virtualisasikan awalan yang dimuat dan tingkatkan tinggi logisnya seiring kedatangan halaman. Jangan berpura-pura bahwa indeks 73.421 yang belum dimuat tersedia secara lokal kecuali API mendukung akses terindeks atau mengembalikan placeholder dengan posisi stabil. Rentang yang terlihat dapat memicu pengambilan saat ujungnya mendekati jumlah yang dimuat, tetapi loader tetap bertanggung jawab untuk menggabungkan (coalescing) permintaan dan berhenti di bagian akhir.
Pemisahan ini mencegah dua bug umum: pemuatan tak terbatas yang membiarkan ribuan node DOM lama tetap ter-mount, dan virtualizer yang memicu permintaan duplikat setiap kali rentang kecilnya dihitung ulang.
Langkah 2: Turunkan rentang tinggi tetap sebelum menambahkan tinggi variabel
Untuk baris dengan tinggi yang sama, turunkan indeks terlihat pertama dan terakhir dari scrollTop, tinggi viewport, dan tinggi baris. Overscan memperluas rentang tetapi dibatasi pada jumlah yang dimuat. Kanvas dalam dengan tinggi penuh membuat scrollbar; baris yang di-mount diposisikan pada offset logisnya.
function getFixedRange({
scrollTop,
viewportHeight,
rowHeight,
loadedCount,
overscanRows,
}) {
const visibleStart = Math.floor(scrollTop / rowHeight);
const visibleEnd = Math.ceil(
(scrollTop + viewportHeight) / rowHeight,
);
return {
start: Math.max(0, visibleStart - overscanRows),
end: Math.min(loadedCount, visibleEnd + overscanRows),
totalHeight: loadedCount * rowHeight,
};
}Render interval setengah terbuka dari start hingga end, tidak termasuk end. Sebuah baris pada indeks i dimulai pada i * rowHeight. Perbarui rentang dari kontainer scroll, lakukan batch rendering dengan framework, dan hindari membaca tata letak serta menulis gaya berulang kali di dalam satu callback scroll.
Solusi ini lebih disukai ketika desain dapat menerapkan satu tinggi baris atau sejumlah kecil varian yang diketahui. Ini mudah diprediksi, murah, dan mudah dipulihkan. Jangan mengadopsi pengukuran dinamis hanya karena library menyediakannya.
Langkah 3: Ukur baris variabel dan pertahankan offset kumulatif
Baris variabel menggantikan perkalian dengan model ukuran. Mulai setiap baris yang belum diukur dengan perkiraan yang wajar berdasarkan desain kartu sebenarnya. Simpan ukuran terukur berdasarkan ID rekaman, bukan berdasarkan slot DOM yang didaur ulang. Offset awal suatu item adalah jumlah dari ukuran-ukuran sebelumnya, sehingga menemukan item pertama yang terlihat menjadi pencarian di atas offset kumulatif.
Array prefix sederhana mudah dijelaskan tetapi dapat memerlukan banyak offset berikutnya untuk diperbarui ketika satu tinggi berubah. Library virtualizer atau struktur prefix-sum terindeks dapat mengurangi pekerjaan pencarian dan pembaruan. Keputusan wawancara yang penting adalah invariant: setiap baris yang dirender memiliki offset awal logis yang diturunkan dari penyimpanan ukuran yang sama, dan total tinggi kanvas sama dengan jumlah ukuran terukur atau terestimasi saat ini.
Gunakan ResizeObserver atau hook pengukuran library setelah tata letak baris selesai. Cadangkan ruang gambar dari dimensi yang diketahui jika memungkinkan; jika tidak, pemuatan gambar akan menghasilkan pengukuran baru. Abaikan ukuran yang tidak berubah, lakukan koreksi secara batch, dan putuskan sambungan observer untuk baris yang di-unmount. Ukur ulang saat lebar, metrik font, ekspansi, atau perubahan konten dapat mengubah tinggi.
Estimasi diperbolehkan salah. Sistem gagal ketika mengubah offset tanpa kebijakan tentang apa yang harus tetap dilihat pengguna.
Langkah 4: Pertahankan scroll anchor logis
Sebelum menerapkan perubahan ukuran, tangkap ID rekaman pertama yang terlihat dan jarak dari tepi atasnya ke tepi atas viewport. Setelah memperbarui pengukuran dan offset kumulatif, temukan awal baru rekaman tersebut dan atur scroll offset sehingga titik intra-baris yang sama tetap berada di lokasi visual yang sama.
Jika baris yang sepenuhnya berada di atas anchor bertambah 30 piksel, scroll offset biasanya memerlukan koreksi 30 piksel yang sama. Perubahan di bawah anchor tidak memerlukannya. Jika pengguna sedang menyeret scrollbar atau produk sengaja dinavigasikan ke item baru, tunda atau lewati koreksi sesuai dengan kontrak interaksi tersebut.
Browser juga menerapkan scroll anchoring untuk perubahan tata letak biasa. Virtualizer sering menggunakan kanvas sintetis dan baris yang diposisikan secara absolut, sehingga perilaku native mungkin tidak mempertahankan item logis yang dimaksudkan. Uji kombinasinya. Biarkan browser atau virtualizer yang memiliki kompensasi untuk kontainer tertentu; jika penjangkaran manual bersifat otoritatif, nonaktifkan penjangkaran native di sana untuk menghindari koreksi ganda.
Menambahkan rekaman lama di awal (prepending) menggunakan aturan yang sama. Tangkap anchor saat ini, masukkan dan ukur rekaman baru, lalu pulihkan anchor. Menambahkan rekaman langsung di akhir hanya mengikuti akhir jika pengguna sudah berada dalam ambang batas "terbaru" produk; jika tidak, tampilkan tindakan "aktivitas baru" alih-alih memindahkan viewport.
Langkah 5: Sesuaikan overscan dari beban kerja per baris dan perilaku scroll
Overscan menyembunyikan latensi rendering dengan me-mount item tepat di luar viewport. Terlalu sedikit dapat mengekspos ruang kosong selama scroll cepat; terlalu banyak akan membuat ulang DOM, tata letak, memori, dan biaya efek yang seharusnya dihindari oleh virtualisasi. Dengan tinggi variabel, overscan berbasis piksel sering kali lebih stabil daripada jumlah baris tetap karena lima baris kompak dan lima baris yang diperluas mewakili beban kerja dan jarak yang berbeda.
Mulai secara konservatif, rekam trace pada perangkat target, dan sesuaikan berdasarkan bukti. Pertimbangkan arah scroll, kecepatan, biaya rendering baris, decoding gambar, dan latensi pembaruan framework. Overscan bukanlah pengganti untuk memoisasi pekerjaan baris yang mahal, mencadangkan dimensi media, membatalkan efek yang usang, atau mengurangi pembacaan tata letak sinkron.
Pertahankan invariant jumlah node yang ketat: baris yang di-mount sama dengan rentang yang terlihat, overscan, dan sejumlah kecil baris yang disematkan (pinned) secara eksplisit seperti item yang difokuskan. Profil memori harus menunjukkan komponen baris lama, observer, dan event listener dapat dikumpulkan (garbage collected) setelah meninggalkan set tersebut.
Langkah 6: Muat halaman tanpa race condition atau rekaman duplikat
Picu pemuatan dari ujung rentang logis alih-alih mengandalkan sentinel yang mungkin didaur ulang. Izinkan paling banyak satu permintaan per cursor. Simpan cursor yang terkait dengan setiap permintaan, deduplikasi rekaman yang dikembalikan berdasarkan ID stabil, dan berhenti saat server menyatakan tidak ada cursor berikutnya.
Pemfilteran atau pengurutan membuat generasi kueri baru. Batalkan permintaan sebelumnya jika memungkinkan dan tolak setiap respons terlambat yang generasinya tidak lagi cocok. Atur ulang ID berurutan, cursor, pengukuran yang bergantung pada tata letak atau konten, dan posisi scroll sesuai dengan kontrak produk. Menggunakan kembali offset lama untuk urutan baru akan melampirkan tinggi yang benar ke posisi yang salah.
Placeholder pemuatan membutuhkan perlakuan logis yang stabil. Jika satu placeholder mewakili halaman berikutnya, itu bukan 50 rekaman yang dapat diakses. Jika API menyediakan total terindeks yang diketahui dan produk memilih placeholder per-baris, berikan posisi stabil dan ganti tanpa mengubah identitas. Selalu ekspos status coba lagi dan akhir daftar; pengambilan yang gagal tidak boleh meninggalkan ekor kosong permanen yang terlihat seperti akhir dari daftar.
Langkah 7: Simpan identitas rekaman dan status penting di luar baris yang didaur ulang
Gunakan ID stabil setiap rekaman sebagai kunci framework dan kunci item virtualizer. Indeks array tidak aman saat halaman ditambahkan di awal, filter menyusun ulang rekaman, atau duplikat dihapus. Slot yang didaur ulang dapat menampilkan rekaman A sekarang dan rekaman B nanti; status yang terikat pada slot dapat membocorkan draf, kotak centang, atau hasil optimistik antar rekaman pengguna.
Simpan status UI yang tahan lama sebagai peta yang diberi kunci berdasarkan ID rekaman: teks draf, ekspansi, seleksi, status validasi, dan mutasi tertunda. Sebuah baris membaca bagiannya saat di-mount dan menulis melalui pemilik yang bertahan dari unmounting. Status lokal dapat diterima untuk detail presentasi sementara yang kehilangannya disengaja.
Jangan menyimpan setiap nilai sementara selamanya. Hapus status saat produk membuang kueri, batasi retensi draf, dan rekonsiliasikan status optimistik dengan hasil server. Tujuannya adalah kepemilikan berdasarkan identitas bisnis, bukan cache klien tanpa batas.
Langkah 8: Rancang aksesibilitas sebagai bagian dari algoritma rentang
Pilih semantik dari interaksi. Untuk feed bacaan, kontainer dapat menggunakan semantik feed dan setiap kartu menggunakan semantik article dengan nama yang dapat diakses. Setiap article yang di-mount mengekspos posisi logis berbasis-satu. Jika totalnya diketahui, ekspos total logis; jika tidak diketahui, gunakan representasi ukuran-tidak-diketahui dari pola tersebut. Tandai feed sebagai sibuk selama pembaruan multi-operasi dan selalu hapus status tersebut saat pembaruan selesai.
Jangan meng-unmount elemen yang berisi fokus DOM. Tambahkan rekaman yang difokuskan ke rentang yang di-mount meskipun berada di luar overscan normal, atau pindahkan fokus melalui tindakan navigasi yang disengaja sebelum penggusuran (eviction). Ketika perintah keyboard berpindah ke article logis berikutnya, pastikan article tersebut dimuat dan di-mount, scroll ke dalam tampilan, lalu fokuskan. Dokumentasikan tombol kustom apa pun dan pertahankan cara yang andal untuk berpindah sebelum dan sesudah feed.
Virtualisasi juga dapat merusak fitur cari-di-halaman (find-in-page), pemilihan teks browser, pencetakan, dan perilaku penjelajahan screen-reader karena konten di luar layar tidak ada di DOM. Putuskan apakah fitur-fitur tersebut merupakan persyaratan. Pencarian mungkin memerlukan kontrol yang didukung server, pencetakan dapat merender tampilan terpaginasi terpisah, dan kontrol "Muat lebih banyak" yang eksplisit dapat memberikan alternatif yang dapat dioperasikan untuk pemuatan otomatis.
Terakhir, uji dengan operasi khusus keyboard dan pembaca layar yang sebenarnya. Memeriksa atribut mengonfirmasi markup tetapi tidak dapat membuktikan bahwa fokus, pengumuman, pemuatan, dan navigasi bekerja bersama.
Langkah 9: Validasi matriks kegagalan, bukan hanya satu scroll yang mulus
Bangun kumpulan data deterministik yang berisi teks pendek dan panjang, gambar tertunda dengan dimensi, ekspansi, media yang hilang, dan ID duplikat. Lakukan scroll roda lambat dan cepat, momentum sentuh, menyeret scrollbar, mengubah ukuran, zoom, pemuatan font, perubahan filter selama permintaan, prepend, append, kegagalan fetch, coba lagi, dan akhir data.
Rekam jumlah baris yang di-mount dan node DOM di seluruh proses. Gunakan performance trace untuk memeriksa frame, long tasks, scripting, layout, paint, dan pengukuran berulang yang tidak terduga. Lacak memori puncak dan yang dipertahankan setelah menggulir banyak halaman. Bandingkan anchor logis teratas sebelum dan sesudah perubahan tinggi, dan pastikan cursor dan ID duplikat tidak muncul.
Untuk interaksi, tempatkan fokus pada baris, scroll dengan pointer dan keyboard, perluas baris di atasnya, muat halaman berikutnya, dan ubah filter. Verifikasi di mana fokus mendarat dan apakah draf tetap terlampir pada ID yang benar. Dengan screen-reader, verifikasi nama article, posisi logis dan ukuran set, transisi status sibuk, navigasi berikutnya dan sebelumnya, coba lagi, dan status akhir.
Target penerimaan adalah milik produk dan perangkat target. Laporkan trace yang diukur dan pelanggaran invariant alih-alih mengklaim bahwa virtualisasi menjamin frame rate tertentu.
Contoh jawaban berkualitas tinggi
"Saya akan memodelkan feed sebagai tiga lapisan. Lapisan data memiliki ID berurutan, rekaman, cursor berikutnya, generasi permintaan, dan deduplikasi. Virtualizer hanya menerima ID yang dimuat dan memiliki rentang yang terlihat, pengukuran, dan pemosisian. Draf, ekspansi, seleksi, dan mutasi berada di peta yang diberi kunci berdasarkan ID rekaman sehingga meng-unmount baris tidak menghapus atau memindahkannya.
Untuk baris tetap, rentang adalah aritmatika offset langsung dan tinggi kanvas adalah jumlah yang dimuat dikalikan tinggi baris. Kartu-kartu ini bervariasi dari 48 hingga 240 piksel, jadi saya akan mulai dari estimasi, mengukur kartu yang di-mount, dan mempertahankan offset kumulatif. Rekaman pertama yang terlihat dan offset intra-barisnya membentuk scroll anchor. Ketika pengukuran di atas rekaman itu berubah, saya memperbarui scroll offset dengan delta yang dihasilkan. Saya akan memilih satu pemilik kompensasi untuk kontainer sehingga scroll anchoring native dan manual tidak saling menyesuaikan.
Rentang mencakup overscan terukur kecil ditambah kartu apa pun yang difokuskan. Ketika ujungnya mendekati jumlah yang dimuat, loader meminta cursor berikutnya satu kali. Perubahan filter memulai generasi baru, membatalkan permintaan lama jika memungkinkan, menolak hasil yang terlambat, dan mengatur ulang urutan serta pengukuran. ID rekaman berfungsi sebagai kunci item; indeks tidak pernah memiliki status.
Untuk aksesibilitas, aliran aktivitas ini menggunakan semantik feed dan article. Article yang terpasang mengekspos posisi logis dan total yang diketahui, feed mengekspos status sibuk saat halaman dimasukkan, dan status tersebut dibersihkan setelahnya. Saya tidak meng-unmount article yang berisi fokus. Navigasi keyboard memuat dan me-mount article logis berikutnya sebelum memfokuskannya, dan saya mempertahankan jalur coba lagi, akhir, dan muat lebih banyak yang eksplisit.
Pertama-tama saya akan mengonfirmasi apakah rendering biasa gagal memenuhi anggaran target. Kemudian saya akan menguji campuran deterministik dari tinggi baris, media yang tertunda, ekspansi, scroll cepat, pengubahan ukuran, race condition filter, prepend dan append, serta kegagalan jaringan. Saya akan merekam jumlah node yang terpasang, long tasks, pekerjaan tata letak dan paint, memori yang tertahan, kesalahan anchor, permintaan dan ID duplikat, identitas draf, fokus keyboard, dan output screen-reader. Jika daftar normal yang dipaginasi memenuhi persyaratan yang sama, saya akan memilihnya karena memiliki lebih sedikit mode kegagalan kebenaran dan aksesibilitas."
Kesalahan umum
- Memperlakukan pemuatan tak terbatas sebagai virtualisasi → halaman lama terus menambahkan node DOM dan performa menurun seiring bertambahnya jarak scroll → batasi rentang yang ter-mount secara independen dari data yang dimuat.
- Menggunakan indeks array sebagai kunci item → prepend, pemfilteran, dan deduplikasi memindahkan draf dan seleksi ke rekaman yang berbeda → kunci baris dan status eksternal berdasarkan ID rekaman yang stabil.
- Mengasumsikan satu tinggi rata-rata adalah tepat → kesalahan offset terakumulasi dan menyebabkan rentang kosong atau lompatan → ukur baris variabel dan perbarui satu model ukuran kumulatif.
- Menerapkan perubahan pengukuran tanpa anchor → konten di atas viewport menggeser apa yang sedang dibaca pengguna → pertahankan rekaman pertama yang terlihat dan offset intra-barisnya.
- Membiarkan penjangkaran native dan manual saling mengompensasi → viewport dapat bergeser dua kali → uji kontainer dan tetapkan kompensasi ke satu pemilik.
- Melakukan overscan pada jumlah baris besar yang tetap → kartu yang diperluas menciptakan kembali beban DOM dan tata letak yang berat → sesuaikan jarak piksel dan biaya rendering pada perangkat target.
- Memicu fetch dari setiap pembaruan rentang → rendering berulang meminta cursor yang sama dan menyisipkan hasil yang tumpang tindih → gabungkan berdasarkan cursor dan tolak generasi kueri yang usang.
- Menyimpan draf di dalam komponen baris → unmounting menghapusnya atau penggunaan kembali slot membocorkannya → angkat status penting ke pemilik yang diberi kunci ID.
- Meng-unmount baris yang difokuskan → konteks keyboard dan teknologi asistif menghilang → sematkan item yang difokuskan atau pindahkan fokus dengan sengaja sebelum penggusuran.
- Hanya melaporkan posisi subset yang ter-mount → pembaca layar mendengar ukuran dan urutan koleksi yang menyesatkan → ekspos posisi logis dan ukuran set logis yang diketahui atau tidak diketahui.
- Mengatur status sibuk dan tidak pernah menghapusnya → teknologi asistif mungkin tidak mengekspos pembaruan yang telah selesai → hapus status sibuk di setiap jalur keberhasilan dan kegagalan.
- Hanya mengoptimalkan frame rate → fokus, draf, race conditions, memori, dan posisi scroll masih bisa salah → validasi performa dan interaksi invariant bersama-sama.
Pertanyaan lanjutan dan tanggapan
Pertanyaan lanjutan 1: Apa yang berubah jika setiap baris tingginya tepat 56 piksel?
Hapus pengukuran dinamis dan jalur koreksinya. Hitung rentang dan offset secara langsung dari 56 piksel, turunkan total tinggi yang dimuat dengan perkalian, dan pulihkan posisi berdasarkan indeks ditambah offset intra-baris. Pertahankan ID stabil, penanganan race condition pemuatan, fokus, dan aksesibilitas; tinggi tetap menyederhanakan geometri tetapi tidak menyelesaikan identitas atau interaksi. Lakukan benchmark sebelum menambahkan struktur prefix-sum yang tidak lagi dibutuhkan oleh batasan tersebut.
Pertanyaan lanjutan 2: Bagaimana Anda mendukung total yang tidak diketahui dari cursor-only API?
Virtualisasikan awalan yang dimuat dan perbesar kanvas saat halaman tiba. Jangan membuat indeks yang belum dimuat atau ukuran scrollbar akhir palsu. Ekspos ukuran set yang tidak diketahui dari pola feed, umumkan status pemuatan dan akhir, dan pertahankan kontrol muat lebih banyak atau coba lagi yang eksplisit. Lompatan arbitrer ke indeks tidak tersedia kecuali server menambahkan pencarian terindeks, pencari rekaman, atau kontrak estimasi yang stabil.
Pertanyaan lanjutan 3: Item lama ditambahkan di awal saat pengguna membaca bagian tengah. Bagaimana cara menghentikan lompatan?
Tangkap ID rekaman pertama yang terlihat dan offset relatif viewport-nya sebelum penyisipan. Masukkan ID yang lebih lama, estimasi atau ukur, hitung ulang offset kumulatif, dan atur scroll offset sehingga rekaman yang ditangkap kembali ke titik visual yang sama. Deduplikasi ID di batas halaman. Jika pengukuran berlanjut setelah media dimuat, terapkan delta berikutnya di atas anchor menggunakan aturan yang sama.
Pertanyaan lanjutan 4: Kartu yang difokuskan berjarak 5.000 item setelah pengguna menyeret scrollbar. Apakah Anda tetap me-mount-nya selamanya?
Tentukan kontrak interaksi. Menjaga satu kartu yang difokuskan tetap tersemat adalah biaya DOM yang terbatas, tetapi target fokus tersembunyi yang jauh dari viewport dapat membingungkan pengguna. Selama lompatan scrollbar yang disengaja, pindahkan fokus ke kontainer feed atau article terlihat yang baru dinavigasi dengan pengumuman, lalu lepas sematan kartu lama. Selama pengukuran insidental atau scroll pointer, jangan menghancurkan fokus secara diam-diam. Uji perilaku yang dipilih dengan pengguna keyboard dan screen-reader.
Pertanyaan lanjutan 5: Produk meminta fitur cari-di-halaman browser dan mencetak semua 100.000 item. Bisakah satu DOM tervirtualisasi memenuhinya?
Tidak ada DOM parsial yang andal yang dapat mengekspos teks yang tidak ter-mount ke pencarian browser atau mencetaknya sebagai konten halaman biasa. Perlakukan ini sebagai persyaratan terpisah. Sediakan pencarian yang didukung server yang berpindah ke dan me-mount rekaman yang cocok. Hasilkan ekspor terpaginasi atau tampilan data khusus cetak dengan batas eksplisit alih-alih me-mount 100.000 kartu interaktif untuk sementara dan membekukan halaman.
Pertanyaan lanjutan 6: Bagaimana Anda menguji virtualizer tanpa hanya mengandalkan screenshot?
Uji invariant rentang-tetap murni dan offset-kumulatif dengan input deterministik, lalu jalankan skenario integrasi di browser nyata. Pastikan bahwa ID yang di-mount mencakup rentang yang terlihat dan overscan, ukuran total cocok dengan model ukuran, anchor logis tetap berada dalam toleransi yang disepakati setelah pengukuran, setiap cursor diminta satu kali, dan draf mengikuti ID melalui penyusunan ulang. Tambahkan pemeriksaan keyboard dan screen-reader karena asersi geometri DOM tidak dapat memvalidasi fokus dan pengumuman.