Topik temu duga representatif

Temu duga frontend: gunakan ResizeObserver tanpa layout thrashing

FrontendSederhana
Pasukan Editorial Offer.ccDiterbitkan Dikemas kini

Soalan

Kad papan pemuka yang boleh diubah saiz menukar susun atur berdasarkan lebar bekasnya. Bagaimanakah anda akan menggunakan ResizeObserver tanpa layout thrashing, gelung maklum balas, langganan pendua, atau kemas kini selepas unmount?

Gesaan dan skop

Kad papan pemuka menukar susun atur berdasarkan bekasnya sendiri dan bukannya viewport. Pelaksanaan pertama membaca dan menulis gaya secara segerak di dalam panggilan balik ResizeObserver, menyebabkan bingkai perlahan dan ralat gelung yang sekali-sekala. Reka bentuk pemerhatian, pengukuran, kemas kini, dan pembersihan. Kemahiran teras adalah susun atur pelayar dan kitaran hayat komponen, jadi ini tergolong dalam frontend.

Perkara yang dinilai oleh penemu duga

Jawapan harus membezakan pertanyaan media viewport daripada pemerhatian elemen serta merangkumi pemasaan panggilan balik, pilihan kotak, pemisahan baca/tulis, perlindungan gelung, kemas kini berkelompok, React Strict Mode, berbilang sasaran, elemen tersembunyi, SSR, dan kebolehcapaian.

Soalan untuk dijelaskan terlebih dahulu

  • Adakah kita memerhati content box, border box, atau device-pixel content box?
  • Adakah kemas kini menukar kelas, pemboleh ubah CSS, dimensi Canvas, atau geometri DOM?
  • Adakah panggilan balik akan menukar saiz elemen yang diperhatikan atau saiz keturunannya (ancestor)?
  • Berapakah bilangan sasaran yang wujud, dan patutkah kemas kini digabungkan ke dalam bingkai seterusnya?
  • Bagaimanakah penciptaan dan pembersihan pemerhati dikendalikan semasa unmount, keadaan tersembunyi, dan SSR?

Rangka kerja jawapan 30 saat

“Cipta satu pemerhati yang stabil pada klien dan perhatikan kotak yang diperlukan. Dalam panggilan balik, kumpulkan saiz terlebih dahulu, kemudian pisahkan pembacaan DOM daripada penulisan. Gunakan kelas atau pemboleh ubah CSS dalam bingkai berkelompok supaya perubahan susun atur tidak dapat memberi maklum balas serta-merta kepada sasaran yang diperhatikan. Abaikan nilai yang tidak berubah; semasa unmount, hentikan kemas kini, lakukan unobserve, dan putuskan sambungan (disconnect). Uji tugasan panjang, bilangan susun atur, ralat gelung, dan pemasangan semula Strict Mode.”

Penyelesaian langkah demi langkah

ResizeObserver memerhatikan content box atau border box sesuatu elemen, secara bebas daripada viewport. Pilih kotak secara sengaja: titik henti susun atur biasanya menggunakan saiz content atau border, manakala lukisan tepat piksel mungkin menggunakan device-pixel content. Jangan baca sifat yang memaksa susun atur secara berulang kali di dalam panggilan balik.

Mula-mula kumpulkan saiz terkini setiap entri ke dalam set menunggu yang kecil, kemudian kira titik henti bersama-sama. Simpan pembacaan geometri dalam satu kelompok dan tulis pemboleh ubah CSS atau kelas selepas pengiraan. Jika penulisan boleh menjejaskan susun atur, jadualkannya dengan requestAnimationFrame dan bandingkan kelompok seterusnya dengan nilai sebelumnya.

Gelung maklum balas adalah "perhatikan saiz, tulis gaya, tukar saiz lagi." Contohnya, lebar menukar padding dan padding menukar lebar. Tambahkan histeresis, kekangan bekas tetap, atau kemas kini sifat yang tidak mengubah sasaran yang diukur. Jika pengubahan saiz diperlukan, hadkan kerja kepada satu kemas kini bagi setiap bingkai dan kesan penumpuan (convergence). Pelayar mungkin menangguhkan pemberitahuan yang tidak menumpu dan melaporkan ralat gelung; mengabaikan ralat bukanlah satu penyelesaian.

Dalam React, cipta pemerhati dalam useLayoutEffect khusus klien atau kesan yang sesuai, dengan ref dan panggilan balik yang stabil. Strict Mode boleh menjalankan persediaan dan pembersihan dua kali, jadi pembersihan mestilah idempoten. Semasa unmount, berhenti menggunakan kemas kini, lakukan unobserve pada sasaran, dan putuskan sambungan. SSR tidak boleh mengakses window atau membina pemerhati.

Bagi kebanyakan kad, kongsi pemerhati dan petakan entry.target kepada keadaan komponen, tetapi pastikan pemilikan jelas supaya satu kad tidak menyekat keseluruhan panggilan balik. Semasa seretan, simpan hanya saiz terkini dan gabungkan kemas kini dalam bingkai animasi dan bukannya menambah debounce sebarangan yang menyebabkan kelengahan susun atur.

Elemen tersembunyi, display:none, pemuatan fon, dan bar tatal boleh mengubah saiz. Sediakan lalai yang boleh digunakan untuk entri awal bersaiz sifar dan beralih selepas pengukuran sah pertama. Utamakan pertanyaan bekas CSS (container queries) untuk titik henti gaya tulen; gunakan ResizeObserver apabila JavaScript mesti memacu Canvas, widget pihak ketiga, atau pengiraan perniagaan.

Sahkan dengan panel Performance semasa menyeret, memuatkan fon, menyembunyikan dan menunjukkan kad, memutar viewport, dan memasang banyak contoh. Pastikan setiap perubahan saiz hanya menyebabkan kerja yang diperlukan, tanpa gelung berterusan, pemerhati pendua, kemas kini pasca-unmount, atau layout thrash yang ketara. Uji operasi papan kekunci dan pembaca skrin juga.

Contoh jawapan berkualiti tinggi

“Saya mencipta ResizeObserver sisi klien yang stabil dan memilih content box atau border box dengan sengaja. Panggilan balik merekodkan entri terkini dan mengira titik henti; ia tidak membaca dan menulis susun atur secara berulang kali. Saya menggunakan pemboleh ubah CSS atau kelas dalam bingkai berkelompok. Jika penulisan mengubah saiz yang diperhatikan, saya menambah histeresis, kekangan, dan semakan penumpuan untuk mengelakkan gelung maklum balas.

Pembersihan React adalah idempoten: hentikan kemas kini semasa unmount, unobserve, dan putuskan sambungan. Banyak kad boleh berkongsi pemerhati dengan penghantaran berasaskan sasaran. Saya menguji pengubahan saiz secara seretan, pemuatan fon, keadaan tersembunyi dan ditunjukkan, serta pemasangan semula Strict Mode, mengukur susun atur, tugasan panjang, ralat gelung, langganan pendua, dan interaksi yang boleh diakses.”

Kesilapan biasa

  • Menganggap ResizeObserver sebagai pertanyaan media viewport → komponen gagal dalam bekas yang berbeza → perhatikan elemen itu sendiri.
  • Membaca dan menulis banyak DOM dalam panggilan balik → susun atur paksa dan thrashing → kelompokkan pembacaan dan tulis pada bingkai seterusnya.
  • Menukar sasaran yang diperhatikan tanpa penumpuan → gelung maklum balas → gunakan histeresis, kekangan, dan pengesanan.
  • Mencipta pemerhati pada setiap render → panggilan balik pendua dan kebocoran memori → ref stabil, kebergantungan, dan pembersihan.
  • Hanya melakukan unobserve tetapi mengekalkan keadaan panggilan balik → kemas kini berterusan selepas unmount → tandakan tidak aktif, unobserve, dan putuskan sambungan.
  • Menggunakan susun atur terbesar pada saiz sifar → paparan pertama melompat secara visual → gunakan keadaan lalai sehingga entri yang sah diperoleh.
  • Menggunakan JavaScript untuk setiap titik henti → kerumitan yang tidak perlu → gunakan pertanyaan bekas apabila CSS mencukupi.
  • Hanya menguji seretan biasa → isu fon, elemen tersembunyi, dan Strict Mode terlepas → rangkumi kitaran hayat dan perubahan sumber.

Soalan susulan dan jawapan

Soalan susulan 1: Bilakah panggilan balik berjalan?

Pelayar mengelompokkan pemberitahuan perubahan saiz selepas susun atur. Perubahan yang tidak menumpu mungkin ditangguhkan dan menimbulkan ralat gelung, jadi panggilan balik tidak boleh menyebabkan perubahan susun atur tanpa batas.

Soalan susulan 2: Mengapa tidak menggunakan window.resize?

Ia mencerminkan perubahan viewport, bukannya kad yang berubah disebabkan oleh grid, bar sisi, atau fon. ResizeObserver memerhatikan elemen secara langsung.

Soalan susulan 3: Bagaimanakah anda memisahkan pembacaan dan penulisan?

Baca saiz daripada entri terlebih dahulu, kira keputusan, kemudian kelompokkan penulisan pemboleh ubah CSS atau kelas, menggunakan requestAnimationFrame apabila diperlukan dan mengabaikan nilai yang tidak berubah.

Soalan susulan 4: Satu pemerhati bagi setiap elemen atau pemerhati kongsi?

Beberapa elemen yang dimiliki secara bebas boleh menggunakan pemerhati berasingan. Banyak sasaran boleh berkongsi satu pemerhati dan menghantar mengikut sasaran, asalkan kerja panggilan balik kekal terhad.

Soalan susulan 5: Apakah yang berlaku selepas display:none?

Anggap saiz sifar sebagai sementara, tunggu entri yang sah selepas ditunjukkan, dan elakkan menulis gelung semasa tersembunyi. Jangan anggap sifar sebagai titik henti kekal.

Soalan susulan 6: Mengapa React Strict Mode mendedahkan pepijat?

Mod pembangunan mungkin menjalankan persediaan dan pembersihan kesan dua kali untuk mendedahkan kesan sampingan yang tidak simetri. Pembersihan mestilah boleh diulang dan tidak meninggalkan pemerhati atau panggilan balik kemas kini.

Soalan susulan 7: Bilakah pertanyaan bekas CSS patut diutamakan?

Gunakan CSS untuk titik henti bekas tulen. Gunakan ResizeObserver apabila saiz mesti memacu Canvas, API pihak ketiga, pengukuran kompleks, atau pengiraan perniagaan.

Sumber awam

Soalan berkaitan