Penjana ialah salah satu fungsi yang paling berkuasa dalam JavaScript, membolehkan kami menulis kod yang boleh dijeda dan disambung semula mengikut keperluan. Tidak seperti fungsi biasa yang melaksanakan semua kod serentak, penjana menggunakan pelaksanaan malas, mengembalikan nilai secara berperingkat, menjadikannya lebih mudah untuk bekerja dengan jujukan data, lelaran atau proses yang berjalan lama.
Dalam JavaScript, penjana ditakrifkan menggunakan kata kunci fungsi*, dan dalam kombinasi dengan kata kunci hasil, membenarkan pelaksanaan fungsi dalam bahagian. Setiap kali kami memanggil fungsi penjana, ia tidak melaksanakan serta-merta, sebaliknya mengembalikan lelaran yang membenarkan pelaksanaan terkawal.
Contoh:
const id = (function* () { let i = 1; while (true) { yield i; i += 1; } })();
Dalam contoh ini, penjana fungsi mengembalikan urutan nombor yang tidak terhingga, di mana setiap nombor dijana dan dikembalikan hanya apabila diperlukan.
Kata kunci hasil menghentikan pelaksanaan penjana dan mengembalikan nilai kepada dunia luar. Pada panggilan fungsi seterusnya (menggunakan next()), penjana meneruskan di mana ia berhenti.
Bagaimanakah rupa memanggil penjana:
console.log(id.next().value); // 1 console.log(id.next().value); // 2 console.log(id.next().value); // 3
Setiap panggilan ke next() mengembalikan nilai tatasusunan seterusnya dan menjeda fungsi pada hasil seterusnya.
Malas:
Penjana tidak melaksanakan semuanya sekaligus, tetapi menghasilkan nilai hanya apabila ia diperlukan. Ini sesuai untuk bekerja dengan urutan tak terhingga atau tatasusunan data yang besar.
Kawalan aliran:
Kemungkinan menjeda dan menyambung semula fungsi membolehkan kawalan yang lebih baik terhadap proses yang berjalan lama.
Kecekapan:
Daripada menyimpan semua nilai dalam memori, penjana mengembalikan satu demi satu, yang mengurangkan penggunaan memori.
Walaupun penjana berguna, ia mempunyai beberapa masalah yang berpotensi:
Kawalan aliran kompleks:
Menjeda dan menyambung semula boleh menjadikan kod lebih sukar untuk difahami dan nyahpepijat, terutamanya dalam senario yang rumit.
Prestasi:
Dalam sesetengah kes, menjeda dan menyambung semula kod boleh memperkenalkan overhed tambahan, yang boleh mengurangkan kecekapan.
Terhad:
Satu nilai dikembalikan setiap panggilan, yang boleh menjadi tidak cekap jika banyak data perlu diakses sekali gus.
Keserasian:
Penjana adalah sebahagian daripada standard ECMAScript 2015 (ES6), jadi pelayar lama mungkin tidak menyokongnya tanpa alatan tambahan seperti Babel.
Jika penjana memperkenalkan terlalu banyak kerumitan, anda boleh mempertimbangkan alternatif:
Fungsi rekursif dengan panggil balik:
function generateID(callback, start = 1) { callback(start); setTimeout(() => generateID(callback, start + 1), 0); }
Kelebihan:
Kawalan aliran yang lebih mudah: Walaupun ia menggunakan rekursi, fungsi ini lebih mudah dibaca dan jelas dari segi mengawal aliran program.
Pelaksanaan tak segerak: Menggunakan setTimeout mendayakan operasi tak segerak, yang membantu mengekalkan prestasi.
Kelemahan:
Overhed rekursi: Untuk bilangan lelaran yang sangat besar, masalah rekursi (limpahan tindanan) mungkin berlaku.
Gelung:
Gelung mudah yang menjana bilangan nilai yang telah ditetapkan mungkin merupakan pilihan yang lebih cekap untuk tatasusunan yang lebih kecil.
function generateIDs(limit) { const ids = []; for (let i = 1; i <= limit; i++) { ids.push(i); } return ids; } const ids = generateIDs(100); // Generiše prvih 100 ID-eva console.log(ids);
Kelebihan:
Pelaksanaan mudah: Penyelesaian ini mudah difahami dan tiada masalah dengan kawalan aliran.
Penjanaan pantas: Semua nilai dijana serentak, yang boleh menjadi lebih cekap untuk lebih sedikit lelaran.
Kelemahan:
Penggunaan memori: Semua nilai disimpan dalam memori, yang boleh menjadi masalah untuk tatasusunan yang besar.
Tiada kemalasan: Semua ID adalah pra-jana, yang boleh menjadi tidak cekap jika anda tidak memerlukan semuanya.
Pelajar:
Objek yang mengembalikan nilai boleh lelar melalui kaedah .next(), serupa dengan penjana, tetapi dengan lebih kawalan.
function createIDIterator() { let i = 1; return { next() { return { value: i++, done: false }; } }; } const idIterator = createIDIterator(); console.log(idIterator.next().value); // 1 console.log(idIterator.next().value); // 2 console.log(idIterator.next().value); // 3
Kelebihan:
Kawalan aliran: Mempunyai fungsi yang serupa dengan penjana, tetapi pelaksanaan lebih linear.
Kod yang lebih ringkas: Tiada hasil, yang boleh menjadikan kod lebih mudah untuk diikuti.
Kelemahan:
Tiada jeda automatik: Anda perlu mengurus lelaran secara manual, yang boleh menyusahkan dalam sesetengah kes.
Generasi tak segerak dengan tak segerak/menunggu
Jika ID dijana secara tidak segerak, anda boleh menggunakan async/menunggu dengan fungsi yang mengembalikan janji.
async function generateID(start = 1) { let i = start; while (true) { await new Promise((resolve) => setTimeout(resolve, 0)); console.log(i++); } } generateID();
Kelebihan:
Pelaksanaan tak segerak: Pengendalian cekap bagi operasi jangka panjang tanpa menyekat aliran utama pelaksanaan.
Sintaks moden: async/wait ialah cara yang lebih moden dan intuitif untuk bekerja dengan kod tak segerak.
Kelemahan:
Tidak sesuai untuk kod segerak: Jika anda memerlukan penjanaan segerak, penyelesaian ini tidak sesuai.
Penjana ialah alat yang hebat untuk bekerja dengan tatasusunan data yang besar dan tidak terhingga, serta untuk kawalan aliran dalam aplikasi yang memerlukan proses menjeda dan menyambung semula. Walau bagaimanapun, masalah kerumitan dan potensi prestasi mereka bermakna mereka harus digunakan dengan berhati-hati. Penyelesaian alternatif seperti lelaran, rekursi atau kod tak segerak mungkin lebih sesuai bergantung pada keperluan aplikasi.
Atas ialah kandungan terperinci Memahami Penjana JavaScript: Alat Kawalan Aliran Kod yang Berkuasa. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!