Rumah  >  Artikel  >  hujung hadapan web  >  Pemahaman mendalam tentang mekanisme gelung peristiwa Node (EventLoop).

Pemahaman mendalam tentang mekanisme gelung peristiwa Node (EventLoop).

青灯夜游
青灯夜游ke hadapan
2023-03-16 20:11:321882semak imbas

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!

Pemahaman mendalam tentang mekanisme gelung peristiwa Node (EventLoop).

Walaupun js boleh dilaksanakan dalam penyemak imbas dan node, mekanisme gelung peristiwa mereka tidak sama. Dan terdapat perbezaan yang besar.

Tinjauan keseluruhan mekanisme EventLoop

Sebelum bercakap tentang Node mekanisme gelung acara, mari kita bincangkan dua soalan dahulu

Mengapa perlu kita belajar mekanisme gelung Acara?

Mempelajari gelung acara boleh membolehkan pembangun memahami cara JavaScript beroperasi.

Apakah yang dilakukan oleh mekanisme gelung peristiwa?

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.

Enam fasa EventLoop

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

Pemasa

Timers: digunakan untuk penyimpanan fungsi panggil balik Pemasa (setlnterval, setTimeout).

Panggil balik belum selesai

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.

terbiar, sediakan

idle,prepare: digunakan secara dalaman oleh sistem. (Kami pengaturcara tidak perlu risau tentang perkara ini)

Poll

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:

  • Jika ada sesuatu yang perlu dilaksanakan dalam baris gilir setlmmediate (semak fasa) fungsi pelarasan. Dalam kes ini tidak akan ada menunggu.
  • Terdapat fungsi panggil balik untuk dilaksanakan dalam baris gilir pemasa, dan tidak akan ada menunggu dalam kes ini. Gelung peristiwa akan beralih ke fasa semakan, kemudian ke fasa Closingcallbacks, dan akhirnya dari fasa pemasa ke gelung seterusnya.

Semak

Check: menyimpan fungsi panggil balik setlmmediate.

Menutup panggilan balik

Closingcallbacks: Laksanakan panggilan balik yang berkaitan dengan acara penutupan, seperti fungsi panggil balik untuk menutup sambungan pangkalan data, dsb.

Macrotasks dan microtasks

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

Tugas Makro

  • setlnterval

  • setimeout

  • setlmmediate

  • I/O

Microtasks

  • Janji.lepas tu

  • Janji.tangkap

  • Janji. akhirnya

  • proses.nextTick

Dalam node, apakah susunan pelaksanaan microtasks dan macrotasks?

Jujukan 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.

Contoh kod

Laksanakan penyegerakan dahulu dan kemudian secara tak segerak

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

Pemahaman mendalam tentang mekanisme gelung peristiwa Node (EventLoop).

Anda boleh melihat bahawa kod segerak dilaksanakan dahulu, dan kemudian gelung acara dimasukkan untuk melaksanakan kod tak segerak, dalam peringkat melaksanakan dua timers panggil balik. setTimeout

Adakah setTimeout akan dilaksanakan sebelum setImmediate? fasa. Dan gelung acara bermula dari fasa . Jadi akan dilaksanakan dahulu dan kemudian

.

setTimeoutAdakah analisis di atas betul-betul betul? timerssetImmediateMari kita lihat contohchecktimerssetTimeoutLaksanakan kod di atas, outputnya adalah seperti berikutsetImmediate

Laksanakan dahulu

dan kemudian
console.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");

Seterusnya mari kita ubah kod di atas, keluarkan penangguhan dan lihat apakah outputnya

Pemahaman mendalam tentang mekanisme gelung peristiwa Node (EventLoop).

Kami menjalankannya tujuh kali, dan kami dapat melihat dua daripadanya ialah Apa yang berlaku kepada

setTimeoutsetImmediate

yang berlari dahulu? Bukankah peringkat
setTimeout(() => {
  console.log("setTimeout");
});

setImmediate(() => {
  console.log("setImmediate");
});
dahulu dan kemudian peringkat

? Bagaimana ia boleh berubah? setImmediate

Malah, ia bergantung pada sama ada panggilan balik tak segerak disediakan sepenuhnya apabila memasuki gelung acara. Untuk contoh awal, kerana terdapat kelewatan selama 2000 milisaat, panggilan balik

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 Pemahaman mendalam tentang mekanisme gelung peristiwa Node (EventLoop). tidak semestinya disediakan sepenuhnya, jadi akan ada. ketibaan pertama dalam peringkat 🎜>, dan kemudian laksanakan panggilan balik

dalam peringkat timers gelung acara seterusnya. check

Dalam keadaan apakah fungsi panggil balik

akan diutamakan berbanding panggilan balik setTimeout untuk masa tunda yang sama? setTimeoutcheck 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

dan seterusnya

. setImmediatesetTimeout Mari kita ambil peringkat

sebagai contoh dan tulis kedua-dua ini dalam operasi IO.

timerscheck Mari kita laksanakannya tujuh kali Anda dapat melihat bahawa setiap kali, Pendingcallbacks、idle,prepare、poll dilaksanakan terlebih dahulu. checktimers

pollJadi secara amnya, dengan masa kelewatan yang sama,

tidak 100% dilaksanakan sebelum
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");

我们运行一下看结果,可以看到它是先执行了微任务然后再执行宏任务

Pemahaman mendalam tentang mekanisme gelung peristiwa Node (EventLoop).

nextTick优于其它微任务

在微任务中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后面,它也是先执行的。

Pemahaman mendalam tentang mekanisme gelung peristiwa Node (EventLoop).

微任务穿插在各个阶段间执行

怎么理解这个穿插呢?其实就是在事件循环的六个阶段每个阶段执行完后会清空微任务队列。

我们来看例子,我们建立了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");
  });
});

我们来执行上面的代码

Pemahaman mendalam tentang mekanisme gelung peristiwa Node (EventLoop).

可以看到,先执行微任务,再执行宏任务。先process.nextTick -> Promise.resolve。并且如果微任务继续产生微任务则会再次清空,所以就又输出了nextTick Promise.resolve

接下来到timer阶段,输出setTimeout,并且产生了一个微任务,再进入到下个阶段前需要清空微任务队列,所以继续输出setTimeout Promise.resolve

接下来到check阶段,输出setImmediate,并且产生了一个微任务,再进入到下个阶段前需要清空微任务队列,所以继续输出setImmediate Promise.resolve

这也就印证了微任务会穿插在各个阶段之间运行。

Pemahaman mendalam tentang mekanisme gelung peristiwa Node (EventLoop).

总结

所以对于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!

Kenyataan:
Artikel ini dikembalikan pada:juejin.cn. Jika ada pelanggaran, sila hubungi admin@php.cn Padam