1. Pertanyaan
Sebuah halaman memperbarui hasil pencarian saat pengguna mengetik sembari mengurai indeks offline dan melakukan prefetch halaman berikutnya. Rancang lapisan tugas menggunakan Prioritized Task Scheduling API: pembaruan yang terlihat harus berjalan dengan cepat tanpa prefetch latar belakang memblokir input. Jelaskan scheduler.postTask(), scheduler.yield(), sinyal pembatalan, dan perilaku saat API tidak tersedia.
2. Batasan dan klarifikasi
- Semua tugas berjalan dalam satu event loop window atau Worker; fungsi sinkron yang panjang tetap memblokir thread tersebut.
- Klasifikasikan pekerjaan setidaknya ke dalam prioritas
user-blocking,user-visible, danbackground. - Pengguliran (scrolling), perubahan rute, atau input baru dapat membuat pekerjaan menjadi usang, sehingga pekerjaan tersebut harus dapat dibatalkan atau diprioritaskan ulang.
- Pertahankan fallback yang berfungsi; kebenaran logika bisnis tidak boleh bergantung pada dukungan peramban.
3. Pendekatan utama
scheduler.postTask(callback, options) mengantrekan callback dengan suatu prioritas dan mengembalikan Promise. priority dapat berupa user-blocking, user-visible, atau background. Teruskan AbortSignal untuk membatalkan; TaskController bersama juga dapat mengubah prioritas tugas yang belum dimulai. scheduler.yield() memungkinkan fungsi async secara sukarela mengembalikan kendali ke peramban sebelum melanjutkan.
Prioritas mengubah urutan eksekusi; prioritas tidak melakukan preemption terhadap JavaScript yang sedang berjalan. Jaga agar setiap callback tetap singkat dan lakukan yield di antara potongan tugas (chunks). Saat API tidak tersedia, gunakan batch kecil setTimeout atau MessageChannel, atau scheduler framework yang ada, sembari mempertahankan semantik pembatalan dan hasil usang (stale-result) yang sama.
4. Implementasi referensi
const scheduler = globalThis.scheduler;
function scheduleWork(task, priority, signal) {
if (scheduler?.postTask) {
return scheduler.postTask(task, { priority, signal });
}
return new Promise((resolve, reject) => {
const run = () => {
if (signal?.aborted) {
reject(signal.reason);
return;
}
Promise.resolve().then(task).then(resolve, reject);
};
setTimeout(run, priority === "background" ? 50 : 0);
});
}
async function indexInChunks(items, signal) {
for (let i = 0; i < items.length; i += 100) {
await scheduleWork(() => buildIndex(items.slice(i, i + 100)),
"background", signal);
if (scheduler?.yield && i + 100 < items.length) {
await scheduler.yield({ signal });
}
}
}5. Performa dan kebenaran
Prioritas tidak mengubah hasil program atau menginterupsi callback yang sedang berjalan; prioritas hanya memengaruhi urutan relatif dari tugas-tugas yang belum dimulai. Promise dari scheduler.postTask() diselesaikan dengan nilai kembalian callback, sedangkan error pada callback atau pembatalan harus ditangani sebagai rejection oleh pemanggil.
Batasan performa sebenarnya adalah durasi tugas dan total pekerjaan: perulangan sinkron 200 ms tetap memblokir input meskipun ditempatkan di antrean berprioritas rendah. Ukur Long Tasks, input delay, dan hit rate pembatalan per batch, lalu sesuaikan ukuran chunk. Pekerjaan berat CPU yang dapat dijalankan secara paralel mungkin lebih tepat berada di Worker; prioritas saja tidak dapat menyembunyikan thread starvation pada thread utama.
6. Tindak lanjut dan jebakan
- Lakukan deteksi
globalThis.scheduler?.postTaskalih-alih menebak dukungan dari merek atau versi peramban. AbortSignalmembatalkan pekerjaan yang belum dimulai atau yang mengamati sinyal tersebut; ia tidak dapat menghentikan secara paksa callback sinkron yang sudah berjalan.- Prioritas dinamis bukanlah preemption. Jika suatu tugas telah meninggalkan antrean, gunakan pemeriksaan versi tingkat bisnis untuk menghindari penerapan hasil yang usang.
- Fallback
setTimeouttidak dapat mereproduksi semua semantik prioritas native, jadi verifikasi jalur pekerjaan yang terlihat, pekerjaan latar belakang, dan pembatalan secara eksplisit.
7. Bacaan lebih lanjut
Bandingkan scheduler.postTask() dengan requestIdleCallback(), MessageChannel, dan scheduler framework: yang pertama menyediakan prioritas dan pembatalan eksplisit, callback idle bergantung pada peluang idle, message channel hanya mengantrekan pekerjaan, dan framework mungkin menambahkan semantik siklus hidup komponen. Pilih berdasarkan kompatibilitas, jenis tugas, dan perilaku yang terukur.
8. Poin penilaian wawancara
Mampu menjelaskan batasan prioritas
Kandidat harus mencakup tiga prioritas, Promise yang dikembalikan, dan fakta bahwa hanya tugas yang belum dimulai yang diurutkan; ini bukan preemption thread.
Mampu merancang pekerjaan yang dapat dibatalkan
Mereka harus menggunakan AbortSignal atau TaskController, menjelaskan bahwa callback yang sudah dimulai tidak dapat dihentikan secara paksa, dan menambahkan pemeriksaan versi untuk hasil usang.
Mampu menulis progressive fallback
Mereka harus melakukan feature detection terlebih dahulu, kemudian menyediakan penjadwalan melalui timer, message channel, atau framework sembari mempertahankan kelas tugas dan perilaku pembatalan.
Mampu membuktikan manfaatnya dengan data
Mereka harus mengukur Long Tasks, input delay, durasi chunk, dan hit rate pembatalan, serta menyadari bahwa Worker mengisolasi pekerjaan yang benar-benar berat CPU.