Topik wawancara representatif

Wawancara umum: Bagaimana cara Iterator.concat menyusun sumber data lazy?

UmumSulit
Tim Redaksi Offer.ccDipublikasikan Diperbarui

Pertanyaan

Implementasikan sebuah iterator lazy yang menggabungkan sebuah array, sebuah Set, dan sebuah generator, lalu jelaskan batasan antara Iterator.concat, Array.concat, Iterator.from, dan flatMap.

1. Pertanyaan dan cakupan

Sebuah agregator log membaca array dalam memori, Set yang telah dide-duplikasi, dan generator terpaginasi berdasarkan urutan prioritas; konsumen hanya memerlukan 100 rekaman pertama. Gunakan Iterator.concat dengan tetap mempertahankan sifat lazy, dan jelaskan input tak terbatas, pengecualian (exceptions), serta pembersihan ketika konsumsi berhenti lebih awal.

2. Apa yang sedang diuji oleh pewawancara

  • Membedakan Iterable dari Iterator dan mengetahui bahwa Iterator.concat memerlukan argumen Iterable.
  • Menjelaskan bahwa hasilnya adalah Iterator lazy baru yang menarik input secara berurutan hanya saat dikonsumsi.
  • Mengidentifikasi bahwa sumber tak terbatas menyembunyikan setiap sumber berikutnya dan daftar argumen harus tetap terbatas.
  • Menangani pembersihan return, kasus TypeError, fallback kompatibilitas, dan materialisasi array yang tidak perlu.

3. Pertanyaan untuk diklarifikasi terlebih dahulu

  1. Apakah setiap input merupakan Iterable yang dapat diulang atau Iterator sekali pakai yang sudah berjalan?
  2. Apakah konsumen memerlukan antarmuka streaming atau sebuah array pada batasannya?
  3. Apakah ada input yang memiliki kursor berkas, jaringan, atau basis data yang harus ditutup saat berhenti lebih awal?
  4. Apakah peramban target dan Node menyediakan Iterator.concat bawaan, atau apakah polyfill diizinkan?

4. Jawaban tiga puluh detik

Saya akan memverifikasi bahwa setiap argumen mengimplementasikan Symbol.iterator, lalu membuat Iterator lazy dengan Iterator.concat. Iterator ini mengambil setiap input secara berurutan dan membaca nilai hanya ketika konsumen memanggil next, take, atau melakukan spread pada hasilnya. take(100) berhenti menarik nilai dan memberi kesempatan iterator yang mendasarinya untuk menutup. Tempatkan input tak terbatas di posisi terakhir atau batasi konsumsi; pada runtime yang lebih lama, gunakan fallback generator dengan semantik sifat lazy dan pembersihan yang sama.

5. Pembahasan mendalam langkah demi langkah

Langkah 1: Menetapkan batasan Iterable

Iterator.concat menerima Iterable, bukan sekadar objek dengan next. Array, Set, dan objek generator memenuhi syarat. Iterator murni sebaiknya dibungkus terlebih dahulu dengan Iterator.from; ini memberi concat cara yang jelas untuk memperoleh dan menutup setiap iterator input.

Langkah 2: Membangun komposisi lazy

js
function* pages() {
  yield { source: "page", id: 1 };
  yield { source: "page", id: 2 };
}

const memory = [{ source: "memory", id: 1 }];
const unique = new Set([{ source: "set", id: 1 }, { source: "set", id: 2 }]);
const merged = Iterator.concat(memory, unique, pages());
const firstThree = merged.take(3).toArray();

Membuat merged tidak melintasi input apa pun; toArray memulai konsumsi. Nilai-nilai dimunculkan dalam urutan memori, Set, dan halaman, serta concat tidak melakukan de-duplikasi atau mentransformasikannya.

Langkah 3: Memahami status konsumsi

Iterator yang dikembalikan menyimpan input dan posisi saat ini. Setelah satu konsumen memajukannya, konsumen lain hanya melihat sisanya. Mengulang kembali memerlukan Iterator baru dari Iterable sumber. Jika hanya N nilai pertama yang diperlukan, terapkan take setelah concat alih-alih melakukan spread terlebih dahulu.

Langkah 4: Membatasi input tak terbatas

Input apa pun bisa jadi tak terbatas, sehingga membuat hasilnya tak terbatas. Jika input pertama tidak pernah berakhir, input berikutnya tidak dapat dijangkau; tempatkan batch terbatas terlebih dahulu atau terapkan take, batas waktu (timeout), dan pembatalan pada batasan konsumen. Jangan menulis Iterator.concat(...infiniteIterables()), karena melakukan spread pada daftar argumen tidak akan pernah selesai.

Langkah 5: Pembersihan, kesalahan, dan fallback

Ketika konsumsi berhenti atau melempar kesalahan, iterator saat ini harus mendapatkan kesempatan untuk menjalankan return, melepaskan kursor, handle berkas, atau koneksi. Iterator kustom dapat mencatat pembersihan dalam finally. Pada runtime tanpa dukungan bawaan, sebuah generator dapat melakukan yield* pada input secara berurutan dan meneruskan return; fallback tidak boleh menyalin setiap input ke dalam array secara diam-diam.

6. Contoh jawaban berkualitas tinggi

Saya akan memvalidasi input Iterable, membuat komposisi lazy dengan Iterator.concat, dan memanggil take(100) atau toArray hanya pada batasan konsumen. concat mengambil input secara berurutan dan tidak melakukan de-duplikasi nilainya. Input pertama yang tak terbatas membuat sumber berikutnya tidak dapat dijangkau, jadi saya akan membatasi konsumsi dan menguji pembersihan saat berhenti lebih awal melalui return. Untuk runtime yang lebih lama, fallback generator dapat mempertahankan sifat lazy, pengurutan, status sekali pakai, dan pembersihan tanpa mematerialisasi sumber.

7. Kesalahan umum

  • Meneruskan objek yang hanya memiliki next → TypeError → bungkus dengan Iterator.from atau implementasikan Symbol.iterator.
  • Mengasumsikan concat dieksekusi secara langsung → I/O tersembunyi → ingat bahwa konsumsi menarik nilai secara bertahap.
  • Menempatkan Iterable tak terbatas di urutan pertama → sumber berikutnya tidak pernah tercapai → ubah urutan dan batasi konsumsi.
  • Melakukan spread pada semuanya terlebih dahulu → lonjakan memori dan latensi → panggil toArray hanya pada batasan array yang eksplisit.
  • Mengabaikan return saat berhenti lebih awal → kebocoran kursor → uji Iterable penghitung dan pastikan pembersihan berjalan.

8. Pertanyaan lanjutan

Pertanyaan lanjutan 1: Apa perbedaannya dengan Array.concat?

Array concat memproses array yang termaterialisasi secara langsung dan mengembalikan sebuah array. Iterator.concat menerima Iterable dan mengembalikan Iterator lazy yang dapat merepresentasikan generator dan sumber tak terbatas.

Pertanyaan lanjutan 2: Mengapa tidak meneruskan setiap Iterator secara langsung?

Iterator murni yang bukan Iterable membuat kepemilikan dan penutupan input yang belum tercapai menjadi ambigu. Bungkus dengan Iterator.from untuk menetapkan batasan Iterable.

Pertanyaan lanjutan 3: Kapan flatMap lebih disukai?

Ketika input itu sendiri merupakan urutan Iterable yang besar atau tidak terbatas, flatMap dapat menghasilkan dan meratakannya secara bertahap. concat lebih jelas untuk kumpulan input yang terbatas dan diketahui.

Pertanyaan lanjutan 4: Bagaimana cara Anda memverifikasi pembersihan?

Gunakan Iterable pengujian yang mengimplementasikan next dan return, catat penarikan dan penutupan, serta pastikan bahwa take, interupsi konsumen, dan kesalahan callback menghentikan penarikan serta memanggil return.

Sumber publik

Pertanyaan terkait