Urut utama membaca peristiwa daripada "baris gilir tugasan". Proses ini adalah kitaran, jadi keseluruhan mekanisme operasi juga dipanggil Gelung Peristiwa. Artikel berikut akan membantu anda menguasai gelung peristiwa dalam Node.js, saya harap ia akan membantu anda!
Walaupun js
boleh dilaksanakan dalam penyemak imbas dan node
, mekanisme gelung peristiwa mereka tidak sama. Dan terdapat perbezaan yang besar.
Sebelum bercakap tentang Node
mekanisme gelung acara, mari kita bincangkan dua soalan dahulu
Mempelajari gelung acara boleh membolehkan pembangun memahami cara JavaScript
beroperasi.
Mekanisme gelung peristiwa digunakan untuk mengurus apabila fungsi panggil balik API tak segerak kembali ke urutan utama untuk pelaksanaan .
Node.js menggunakan model IO tak segerak. API segerak dilaksanakan dalam utas utama, API tak segerak dilaksanakan dalam utas yang diselenggara oleh C++ asas, dan fungsi panggil balik API tak segerak juga akan dilaksanakan dalam utas utama. [Tutorial berkaitan yang disyorkan: tutorial video nodejs, Pengajaran pengaturcaraan]
Apabila aplikasi Javascript sedang berjalan, bilakah fungsi panggil balik banyak API tak segerak boleh kembali ke utama benang? Inilah yang dilakukan oleh mekanisme gelung peristiwa, mengurus apabila fungsi panggil balik API tak segerak kembali ke utas utama untuk dilaksanakan.
Gelung peristiwa dalam Node
dibahagikan kepada enam fasa.
Terdapat baris gilir pada setiap peringkat dalam gelung acara untuk menyimpan fungsi panggil balik yang akan dilaksanakan Mekanisme gelung acara akan melaksanakannya dalam first-in, first-. luar cara sehingga giliran adalah batal.
Enam peringkat ini semua menyimpan fungsi panggil balik tak segerak, jadi masih perlu untuk melaksanakan kod penyegerakan utas utama dahulu, dan kemudian tinjauan enam peringkat ini selepas kod penyegerakan dilaksanakan.
Seterusnya, mari kita lihat secara terperinci apa yang disimpan dalam enam peringkat ini
Timers
: digunakan untuk penyimpanan fungsi panggil balik Pemasa (setlnterval, setTimeout).
Pendingcallbacks
: Jalankan fungsi panggil balik yang berkaitan dengan sistem pengendalian Contohnya, fungsi panggil balik yang memantau operasi port apabila memulakan aplikasi sebelah pelayan ialah dipanggil ke sini.
idle,prepare
: digunakan secara dalaman oleh sistem. (Kami pengaturcara tidak perlu risau tentang perkara ini)
Poll
: Menyimpan baris gilir fungsi panggil balik untuk operasi 1/O, seperti fungsi panggil balik untuk operasi membaca dan menulis fail.
Perhatian khusus perlu diberikan pada peringkat ini Jika terdapat fungsi panggil balik dalam baris gilir acara, laksanakannya sehingga baris gilir dikosongkan. , jika tidak gelung acara akan kekal pada peringkat ini buat seketika untuk menunggu fungsi panggil balik baharu untuk masuk.
Tetapi untuk ini Menunggu tidak pasti, tetapi bergantung kepada dua syarat berikut:
Check
: menyimpan fungsi panggil balik setlmmediate.
Closingcallbacks
: Laksanakan panggilan balik yang berkaitan dengan acara penutupan, seperti fungsi panggil balik untuk menutup sambungan pangkalan data, dsb.
Seperti js
dalam penyemak imbas, kod tak segerak dalam node
juga dibahagikan kepada makrotasks dan microtasks Terdapat perbezaan dalam susunan pelaksanaan antara mereka.
Mari kita lihat apakah tugasan makro dan tugasan mikro dalam Node
setlnterval
setimeout
setlmmediate
I/O
Janji.lepas tu
Janji.tangkap
Janji. akhirnya
proses.nextTick
Dalam node
, apakah susunan pelaksanaan microtasks dan macrotasks?
Dalam node
, fungsi panggil balik microtask diletakkan dalam baris gilir microtask, dan fungsi panggil balik macrotask diletakkan dalam makro dalam baris gilir tugas.
Tugas mikro mempunyai keutamaan yang lebih tinggi daripada tugas makro. Apabila terdapat fungsi panggil balik boleh laku dalam baris gilir acara microtask, gelung acara akan berhenti seketika dan memasuki peringkat seterusnya gelung acara selepas melaksanakan fungsi panggil balik peringkat semasa, dan akan segera memasuki baris gilir acara microtask untuk mula melaksanakan panggilan balik. fungsi. Apabila fungsi panggil balik dalam baris gilir microtask dilaksanakan, gelung acara akan memasuki segmen seterusnya dan mula melaksanakan fungsi panggil balik.
Ada satu lagi perkara yang perlu kita beri perhatian khusus apabila ia berkaitan dengan tugasan mikro. Iaitu, walaupun nextTick
juga merupakan tugasan mikro, keutamaannya lebih tinggi daripada tugasan mikro lain Apabila melaksanakan tugasan mikro, tugasan mikro lain hanya akan mula dilaksanakan selepas semua fungsi panggil balik dalam nextlick
dilaksanakan.
Secara amnya, apabila kod penyegerakan utas utama dilaksanakan, tugasan mikro akan dikosongkan terlebih dahulu (jika tugasan mikro terus menjana tugasan mikro, ia akan dikosongkan semula), dan kemudian pergi ke peringkat gelung peristiwa seterusnya. Dan perlaksanaan microtasks diselang-seli di antara enam peringkat gelung acara Iaitu, sebelum setiap gelung peristiwa memasuki peringkat seterusnya, ia akan menentukan sama ada baris gilir microtask itu kosong, ia akan memasuki peringkat seterusnya. Jika tidak, microtasks akan dikosongkan terlebih dahulu.
Mari gunakan amalan kod untuk mengesahkan perkara yang kami katakan di atas.
Selepas aplikasi Node
dimulakan, ia tidak akan Masukkan gelung peristiwa dengan serta-merta, tetapi laksanakan kod segerak dahulu, bermula dari atas ke bawah API segerak dilaksanakan dengan serta-merta, API tak segerak diserahkan kepada benang yang diselenggara oleh C++ untuk pelaksanaan, dan fungsi panggil balik API tak segerak ialah. didaftarkan dalam baris gilir acara yang sepadan. Apabila semua kod penyegerakan dilaksanakan, gelung acara akan dimasukkan.
console.log("start"); setTimeout(() => { console.log("setTimeout 1"); }); setTimeout(() => { console.log("setTimeout 2"); }); console.log("end");
Mari kita lihat hasil pelaksanaan
Anda boleh melihat bahawa kod segerak dilaksanakan dahulu, dan kemudian gelung acara dimasukkan untuk melaksanakan kod tak segerak, dalam peringkat < The 🎜> melaksanakan dua timers
panggil balik. setTimeout
setTimeout
Adakah analisis di atas betul-betul betul? timers
setImmediate
Mari kita lihat contohcheck
timers
setTimeout
Laksanakan kod di atas, outputnya adalah seperti berikutsetImmediate
Laksanakan dahulu
dan kemudianconsole.log("start"); setTimeout(() => { console.log("setTimeout"); }); setImmediate(() => { console.log("setImmediate"); }); const sleep = (delay) => { const startTime = +new Date(); while (+new Date() - startTime < delay) { continue; } }; sleep(2000); console.log("end");
setTimeout
setImmediate
setTimeout(() => { console.log("setTimeout"); }); setImmediate(() => { console.log("setImmediate"); });
? Bagaimana ia boleh berubah? setImmediate
mesti sedia apabila memasuki gelung acara. Jadi susunan pelaksanaan tidak akan berubah. Tetapi untuk contoh ini, kerana utas utama tidak mempunyai kod penyegerakan untuk dilaksanakan, ia memasuki gelung acara pada permulaan Walau bagaimanapun, apabila memasuki gelung acara, panggilan balik tidak semestinya disediakan sepenuhnya, jadi akan ada. ketibaan pertama < Laksanakan fungsi panggil balik
dalam peringkat 🎜>, dan kemudian laksanakan panggilan balik dalam peringkat timers
gelung acara seterusnya. check
akan diutamakan berbanding panggilan balik setTimeout
untuk masa tunda yang sama? setTimeout
check
sebenarnya sangat mudah, cuma letakkan kedua-duanya dalam mana-mana peringkat setImmediate
antara peringkat timers
dan peringkat setTimeout
. Kerana selepas peringkat ini dilaksanakan, mereka pasti akan sampai ke peringkat
. setImmediate
setTimeout
Mari kita ambil peringkat
timers
check
Mari kita laksanakannya tujuh kali Anda dapat melihat bahawa setiap kali, Pendingcallbacks、idle,prepare、poll
dilaksanakan terlebih dahulu. check
timers
poll
Jadi secara amnya, dengan masa kelewatan yang sama,
const fs = require("fs"); fs.readFile("./fstest.js", "utf8", (err, data) => { setTimeout(() => { console.log("setTimeout"); }); setImmediate(() => { console.log("setImmediate"); }); });
主线程同步代码执行完毕后,会先执行微任务再执行宏任务。
我们来看下面的例子
console.log("start"); setTimeout(() => { console.log("setTimeout"); }); setImmediate(() => { console.log("setImmediate"); }); Promise.resolve().then(() => { console.log("Promise.resolve"); }); console.log("end");
我们运行一下看结果,可以看到它是先执行了微任务然后再执行宏任务
在微任务中nextTick
的优先级是最高的。
我们来看下面的例子
console.log("start"); setTimeout(() => { console.log("setTimeout"); }); setImmediate(() => { console.log("setImmediate"); }); Promise.resolve().then(() => { console.log("Promise.resolve"); }); process.nextTick(() => { console.log("process.nextTick"); }); console.log("end");
我们运行上面的代码,可以看到就算nextTick
定义在resolve
后面,它也是先执行的。
怎么理解这个穿插呢?其实就是在事件循环的六个阶段每个阶段执行完后会清空微任务队列。
我们来看例子,我们建立了timers、check、poll
三个阶段,并且每个阶段都产生了微任务。
// timers阶段 setTimeout(() => { console.log("setTimeout"); Promise.resolve().then(() => { console.log("setTimeout Promise.resolve"); }); }); // check阶段 setImmediate(() => { console.log("setImmediate"); Promise.resolve().then(() => { console.log("setImmediate Promise.resolve"); }); }); // 微任务 Promise.resolve().then(() => { console.log("Promise.resolve"); }); // 微任务 process.nextTick(() => { console.log("process.nextTick"); Promise.resolve().then(() => { console.log("nextTick Promise.resolve"); }); });
我们来执行上面的代码
可以看到,先执行微任务,再执行宏任务。先process.nextTick -> Promise.resolve
。并且如果微任务继续产生微任务则会再次清空,所以就又输出了nextTick Promise.resolve
。
接下来到timer
阶段,输出setTimeout
,并且产生了一个微任务,再进入到下个阶段前需要清空微任务队列,所以继续输出setTimeout Promise.resolve
。
接下来到check
阶段,输出setImmediate
,并且产生了一个微任务,再进入到下个阶段前需要清空微任务队列,所以继续输出setImmediate Promise.resolve
。
这也就印证了微任务会穿插在各个阶段之间运行。
所以对于Node
中的事件循环你只需要背好一以下几点就可以了
当主线程同步代码执行完毕后才会进入事件循环
事件循环总共分六个阶段,并且每个阶段都包括哪些回调需要记清楚。
事件循环中会先执行微任务再执行宏任务。
微任务会穿插在这六个阶段之间执行,每进入到下个阶段前会清空当前的微任务队列。
微任务中process.nextTick
的优先级最高,会优先执行。
更多node相关知识,请访问:nodejs 教程!
Atas ialah kandungan terperinci Pemahaman mendalam tentang mekanisme gelung peristiwa Node (EventLoop).. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!