Saya pikir saya bisa menggambarkan ini dengan cukup baik. Karena nextTick
dipanggil pada akhir operasi saat ini, memanggilnya secara rekursif dapat berakhir memblokir perulangan peristiwa dari melanjutkan. setImmediate
menyelesaikan ini dengan menembakkan pada fase pemeriksaan loop acara, yang memungkinkan loop acara berlanjut secara normal.
┌───────────────────────┐
┌─>│ timers │
│ └──────────┬────────────┘
│ ┌──────────┴────────────┐
│ │ I/O callbacks │
│ └──────────┬────────────┘
│ ┌──────────┴────────────┐
│ │ idle, prepare │
│ └──────────┬────────────┘ ┌───────────────┐
│ ┌──────────┴────────────┐ │ incoming: │
│ │ poll │<─────┤ connections, │
│ └──────────┬────────────┘ │ data, etc. │
│ ┌──────────┴────────────┐ └───────────────┘
│ │ check │
│ └──────────┬────────────┘
│ ┌──────────┴────────────┐
└──┤ close callbacks │
└───────────────────────┘
sumber: https://nodejs.org/en/docs/guides/event-loop-timers-and-nexttick/
Perhatikan bahwa fase pemeriksaan segera setelah fase polling. Ini karena fase polling dan I / O callback adalah tempat yang paling mungkin setImmediate
untuk menjalankan panggilan Anda . Jadi idealnya sebagian besar panggilan itu sebenarnya akan sangat segera, hanya saja tidak secepat nextTick
yang diperiksa setelah setiap operasi dan secara teknis ada di luar loop acara.
Mari kita lihat sedikit contoh perbedaan antara setImmediate
dan process.nextTick
:
function step(iteration) {
if (iteration === 10) return;
setImmediate(() => {
console.log(`setImmediate iteration: ${iteration}`);
step(iteration + 1); // Recursive call from setImmediate handler.
});
process.nextTick(() => {
console.log(`nextTick iteration: ${iteration}`);
});
}
step(0);
Katakanlah kita baru saja menjalankan program ini dan sedang melangkah melalui iterasi pertama dari loop acara. Ini akan memanggil step
fungsi dengan iterasi nol. Kemudian akan mendaftarkan dua penangan, satu untuk setImmediate
dan satu untuk process.nextTick
. Kami kemudian secara rekursif memanggil fungsi ini dari setImmediate
handler yang akan dijalankan pada tahap pemeriksaan berikutnya. The nextTick
handler akan berjalan pada akhir operasi saat ini mengganggu loop acara, jadi meskipun itu telah didaftarkan kedua itu benar-benar akan berjalan pertama.
Urutan akhirnya adalah: nextTick
kebakaran saat operasi saat ini berakhir, loop acara berikutnya dimulai, fase loop peristiwa normal dieksekusi, setImmediate
diaktifkan dan secara rekursif memanggil step
fungsi kami untuk memulai proses dari awal lagi. Operasi saat ini berakhir, nextTick
kebakaran, dll.
Output dari kode di atas adalah:
nextTick iteration: 0
setImmediate iteration: 0
nextTick iteration: 1
setImmediate iteration: 1
nextTick iteration: 2
setImmediate iteration: 2
nextTick iteration: 3
setImmediate iteration: 3
nextTick iteration: 4
setImmediate iteration: 4
nextTick iteration: 5
setImmediate iteration: 5
nextTick iteration: 6
setImmediate iteration: 6
nextTick iteration: 7
setImmediate iteration: 7
nextTick iteration: 8
setImmediate iteration: 8
nextTick iteration: 9
setImmediate iteration: 9
Sekarang mari kita pindahkan panggilan rekursif kita ke step
dalam nextTick
handler kita alih-alih setImmediate
.
function step(iteration) {
if (iteration === 10) return;
setImmediate(() => {
console.log(`setImmediate iteration: ${iteration}`);
});
process.nextTick(() => {
console.log(`nextTick iteration: ${iteration}`);
step(iteration + 1); // Recursive call from nextTick handler.
});
}
step(0);
Sekarang kami telah memindahkan panggilan rekursif ke step
dalam nextTick
handler hal-hal akan berperilaku dalam urutan yang berbeda. Iterasi pertama kami dari loop acara berjalan dan panggilan step
mendaftarkan setImmedaite
penangan serta nextTick
penangan. Setelah operasi saat ini berakhir, nextTick
penangan kami akan melakukan panggilan secara rekursif step
dan mendaftarkan setImmediate
penangan yang lain serta nextTick
penangan yang lain . Karena nextTick
pawang menyala setelah operasi saat ini, mendaftarkan nextTick
pawang dalam nextTick
pawang akan menyebabkan pawang kedua berjalan segera setelah operasi pawang saat ini selesai. The nextTick
penangan akan terus menembak, mencegah event loop arus dari yang pernah melanjutkan. Kami akan melewati semua kaminextTick
penangan sebelum kita melihat setImmediate
api penangan tunggal .
Hasil akhir dari kode di atas adalah:
nextTick iteration: 0
nextTick iteration: 1
nextTick iteration: 2
nextTick iteration: 3
nextTick iteration: 4
nextTick iteration: 5
nextTick iteration: 6
nextTick iteration: 7
nextTick iteration: 8
nextTick iteration: 9
setImmediate iteration: 0
setImmediate iteration: 1
setImmediate iteration: 2
setImmediate iteration: 3
setImmediate iteration: 4
setImmediate iteration: 5
setImmediate iteration: 6
setImmediate iteration: 7
setImmediate iteration: 8
setImmediate iteration: 9
Perhatikan bahwa jika kita tidak menginterupsi panggilan rekursif dan membatalkannya setelah 10 iterasi maka nextTick
panggilan akan terus berulang dan tidak pernah membiarkan loop acara berlanjut ke fase berikutnya. Ini adalah bagaimana nextTick
bisa menjadi pemblokiran ketika digunakan secara rekursif sedangkan setImmediate
akan menyala di loop acara berikutnya dan pengaturan setImmediate
handler lain dari dalam satu tidak akan mengganggu loop acara saat ini sama sekali, yang memungkinkannya untuk melanjutkan menjalankan fase-fase dari loop acara seperti biasa.
Semoga itu bisa membantu!
PS - Saya setuju dengan komentator lain bahwa nama kedua fungsi dapat dengan mudah ditukar karena nextTick
terdengar seperti itu akan menyala di loop acara berikutnya daripada akhir yang sekarang, dan akhir dari loop saat ini lebih "segera "Dari awal loop berikutnya. Oh well, itulah yang kami dapatkan ketika API matang dan orang-orang bergantung pada antarmuka yang ada.