Saya pikir saya bisa menggambarkan ini dengan cukup baik. Karena nextTickdipanggil pada akhir operasi saat ini, memanggilnya secara rekursif dapat berakhir memblokir perulangan peristiwa dari melanjutkan. setImmediatemenyelesaikan 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 setImmediateuntuk menjalankan panggilan Anda . Jadi idealnya sebagian besar panggilan itu sebenarnya akan sangat segera, hanya saja tidak secepat nextTickyang diperiksa setelah setiap operasi dan secara teknis ada di luar loop acara.
Mari kita lihat sedikit contoh perbedaan antara setImmediatedan 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 stepfungsi dengan iterasi nol. Kemudian akan mendaftarkan dua penangan, satu untuk setImmediatedan satu untuk process.nextTick. Kami kemudian secara rekursif memanggil fungsi ini dari setImmediatehandler yang akan dijalankan pada tahap pemeriksaan berikutnya. The nextTickhandler 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: nextTickkebakaran saat operasi saat ini berakhir, loop acara berikutnya dimulai, fase loop peristiwa normal dieksekusi, setImmediatediaktifkan dan secara rekursif memanggil stepfungsi kami untuk memulai proses dari awal lagi. Operasi saat ini berakhir, nextTickkebakaran, 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 stepdalam nextTickhandler 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 stepdalam nextTickhandler hal-hal akan berperilaku dalam urutan yang berbeda. Iterasi pertama kami dari loop acara berjalan dan panggilan stepmendaftarkan setImmedaitepenangan serta nextTickpenangan. Setelah operasi saat ini berakhir, nextTickpenangan kami akan melakukan panggilan secara rekursif stepdan mendaftarkan setImmediatepenangan yang lain serta nextTickpenangan yang lain . Karena nextTickpawang menyala setelah operasi saat ini, mendaftarkan nextTickpawang dalam nextTickpawang akan menyebabkan pawang kedua berjalan segera setelah operasi pawang saat ini selesai. The nextTickpenangan akan terus menembak, mencegah event loop arus dari yang pernah melanjutkan. Kami akan melewati semua kaminextTickpenangan sebelum kita melihat setImmediateapi 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 nextTickpanggilan akan terus berulang dan tidak pernah membiarkan loop acara berlanjut ke fase berikutnya. Ini adalah bagaimana nextTickbisa menjadi pemblokiran ketika digunakan secara rekursif sedangkan setImmediateakan menyala di loop acara berikutnya dan pengaturan setImmediatehandler 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 nextTickterdengar 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.