Rumah  >  Artikel  >  hujung hadapan web  >  Mari kita bincangkan tentang gelung acara dalam Node

Mari kita bincangkan tentang gelung acara dalam Node

青灯夜游
青灯夜游ke hadapan
2023-04-11 19:08:211568semak imbas

Gelung peristiwa ialah bahagian asas Node.js Ia mendayakan pengaturcaraan tak segerak dengan memastikan bahawa utas utama tidak disekat Memahami gelung peristiwa adalah penting untuk membina aplikasi yang cekap. Artikel berikut akan memberi anda pemahaman yang mendalam tentang gelung acara dalam Node.

Mari kita bincangkan tentang gelung acara dalam Node

Anda telah lama menggunakan Node.js, membina beberapa apl, mencuba modul yang berbeza, malah berasa selesa dengan pengaturcaraan tak segerak. Tetapi sesuatu terus mengganggu anda - gelung acara.

Jika anda seperti saya, anda telah menghabiskan berjam-jam membaca dokumentasi dan menonton video cuba memahami gelung acara. Tetapi walaupun sebagai pembangun yang berpengalaman, anda mungkin menghadapi masalah memahami sepenuhnya cara ia berfungsi. Itulah sebabnya saya telah menyediakan panduan visual ini untuk membantu anda memahami sepenuhnya gelung acara Node.js. Jadi, duduklah, ambil secawan kopi dan mari selami dunia gelung acara Node.js. [Cadangan tutorial berkaitan: tutorial video nodejs, Pengajaran pengaturcaraan]

Pengaturcaraan tak segerak dalam JavaScript

Kami akan bermula dari Kajian semula pengaturcaraan tak segerak dalam JavaScript bermula. Walaupun JavaScript digunakan dalam aplikasi web, mudah alih dan desktop, adalah penting untuk diingat bahawa, pada terasnya, JavaScript ialah bahasa berutas tunggal yang segerak, menyekat. Marilah kita memahami ayat ini melalui coretan kod pendek.

// index.js

function A() {
  console.log("A");
}

function B() {
  console.log("B");
}

A()
B()

// Logs A and then B
JavaScript adalah segerak

Jika kita mempunyai dua fungsi yang log mesej ke konsol, maka kod akan dilaksanakan dari atas ke bawah, setiap kali Laksanakan hanya satu baris. Dalam coretan kod di atas, kita melihat bahawa A direkodkan sebelum B.

JavaScript menyekat

JavaScript disekat kerana sifat segeraknya. Tidak kira berapa lama proses sebelumnya mengambil masa, proses berikutnya tidak akan bermula sehingga yang pertama selesai. Dalam coretan kod, jika fungsi A perlu melaksanakan blok kod yang besar, JavaScript perlu melengkapkan operasi itu tanpa bercabang kepada fungsi B. Walaupun sekeping kod ini mengambil masa 10 saat atau seminit.

Anda mungkin pernah mengalami perkara ini dalam penyemak imbas anda. Apabila aplikasi web berjalan dalam penyemak imbas dan melaksanakan beberapa blok kod intensif tanpa mengembalikan kawalan kepada penyemak imbas, penyemak imbas mungkin membeku, yang dipanggil menyekat. Penyemak imbas disekat daripada terus memproses input pengguna dan melaksanakan tugas lain sehingga aplikasi web mengembalikan kawalan pemproses kepada penyemak imbas.

JavaScript adalah satu-benang

Benang ialah proses yang boleh digunakan oleh program JavaScript anda untuk menjalankan tugas. Setiap urutan hanya boleh melaksanakan satu tugas pada satu masa. Tidak seperti bahasa lain yang menyokong multi-threading dan boleh menjalankan pelbagai tugas secara serentak, JavaScript hanya mempunyai satu thread yang dipanggil thread utama yang melaksanakan kod.

Menunggu JavaScript

Seperti yang anda boleh bayangkan, model JavaScript ini menimbulkan masalah kerana kami perlu menunggu data diambil sebelum kami boleh meneruskan pelaksanaan kod. Penantian ini mungkin mengambil masa beberapa saat, di mana kami tidak dapat menjalankan sebarang kod lain. Jika JavaScript meneruskan pemprosesan tanpa menunggu, ralat berlaku. Kita perlu melaksanakan tingkah laku tak segerak dalam JavaScript. Mari pergi ke Node.js dan lihat.

Node.js Runtime

Mari kita bincangkan tentang gelung acara dalam NodeNode.js Runtime ialah persekitaran yang anda boleh gunakan tanpa menggunakan penyemak imbas Gunakan dan jalankan program JavaScript. Teras - masa jalan Node, terdiri daripada tiga komponen utama.

Kebergantungan luaran — seperti V8, libuv, crypto, dll. — adalah ciri yang diperlukan Node.js
  • C++ ciri menyediakan kefungsian seperti akses sistem fail dan rangkaian.
  • Pustaka JavaScript menyediakan fungsi dan alatan yang memudahkan untuk memanggil ciri C++ menggunakan kod JavaScript.
  • Walaupun semua bahagian penting, komponen utama pengaturcaraan tak segerak dalam Node.js ialah libuv.

Libuv

Libuv

ialah perpustakaan sumber terbuka merentas platform yang ditulis dalam bahasa C. Dalam masa jalan Node.js, peranannya adalah untuk menyediakan sokongan untuk mengendalikan operasi tak segerak. Mari kita lihat bagaimana ia berfungsi.

Pelaksanaan kod dalam masa jalan Node.js

让我们来概括一下代码在 Node 运行时中的执行方式。在执行代码时,位于图片左侧的 V8 引擎负责 JavaScript 代码的执行。该引擎包含一个内存堆(Memory heap)和一个调用栈(Call stack)。

每当声明变量或函数时,都会在堆上分配内存。执行代码时,函数就会被推入调用栈中。当函数返回时,它就从调用栈中弹出了。这是对栈数据结构的简单实现,最后添加的项是第一个被移除。在图片右侧,是负责处理异步方法的 libuv。

每当我们执行异步方法时,libuv 接管任务的执行。然后使用操作系统本地异步机制运行任务。如果本地机制不可用或不足,则利用其线程池来运行任务,并确保主线程不被阻塞。

同步代码执行

首先,让我们来看一下同步代码执行。以下代码由三个控制台日志语句组成,依次记录“First”,“Second”和“Third”。我们按照运行时执行顺序来查看代码。

// index.js
console.log("First");
console.log("Second");
console.log("Third");

以下是 Node 运行时执行同步代码的可视化展示。

Mari kita bincangkan tentang gelung acara dalam Node

执行的主线程始终从全局作用域开始。全局函数(如果我们可以这样称呼它)被推入堆栈中。然后,在第 1 行,我们有一个控制台日志语句。这个函数被推入堆栈中。假设这个发生在 1 毫秒时,“First” 被记录在控制台上。然后,这个函数从堆栈中弹出。

执行到第 2 行时。假设到第 2 毫秒了,log 函数再次被推入堆栈中。“Second”被记录在控制台上,并弹出该函数。

最后,执行到第 3 行了。第 3 毫秒时,log 函数被推入堆栈,“Third”将记录在控制台上,并弹出该函数。此时已经没有代码要执行,全局也被弹出。

异步代码执行

接下来,让我们看一下异步代码执行。有以下代码片段:包含三个日志语句,但这次第二个日志语句传递给了fs.readFile() 作为回调函数。

Mari kita bincangkan tentang gelung acara dalam Node

执行的主线程始终从全局作用域开始。全局函数被推入堆栈。然后执行到第 1 行,在第 1 毫秒时,“First”被记录在控制台中,并弹出该函数。然后执行移动到第 2 行,在第 2毫秒时,readFile 方法被推入堆栈。由于 readFile 是异步操作,因此它会转移(off-loaded)到 libuv。

JavaScript 从调用堆栈中弹出了 readFile 方法,因为就第 2 行的执行而言,它的工作已经完成了。在后台,libuv 开始在单独的线程上读取文件内容。在第 3 毫秒时,JavaScript 继续进行到第 5 行,将 log 函数推入堆栈,“Third”被记录到控制台中,并将该函数弹出堆栈。

大约在第 4 毫秒左右,假设文件读取任务已经完成,则相关回调函数现在会在调用栈上执行, 在回调函数内部遇到 log 函数。

log 函数推入到到调用栈,“Second”被记录到控制台并弹出 log 函数 。由于回调函数中没有更多要执行的语句,因此也被弹出 。没有更多代码可运行了 ,所以全局函数也从堆栈中删除 。

控制台输出“First”,“Third”,然后是“Second”。

Libuv 和异步操作

很明显,libuv 用于处理 Node.js 中的异步操作。对于像处理网络请求这样的异步操作,libuv 依赖于操作系统原生机制。对于没有本地 OS 支持的异步读取文件的操作,libuv 则依赖其线程池以确保主线程不被阻塞。然而,这也引发了一些问题。

  • 当一个异步任务在 libuv 中完成时,什么时候 Node 会在调用栈上运行相关联的回调函数?
  • Node 是否会等待调用栈为空后再运行回调函数?还是打断正常执行流来运行回调函数?
  • setTimeoutsetInterval 这类延迟执行回调函数的方法又是何时执行回调函数呢?
  • 如果 setTimeoutreadFile 这类异步任务同时完成,Node 如何决定哪个回调函数先在调用栈上运行?其中一个会有更多的优先级吗?

所有这些问题都可以通过理解 libuv 核心部分——事件循环来得到答案。

Apakah gelung acara?

Secara teknikal, gelung acara hanyalah program C. Tetapi dalam Node.js, anda boleh menganggapnya sebagai corak reka bentuk untuk menyelaraskan pelaksanaan kod segerak dan tak segerak.

Memvisualisasikan Gelung Peristiwa

Gelung acara ialah gelung yang berjalan selagi aplikasi Node.js anda sedang berjalan. Terdapat enam baris gilir yang berbeza dalam setiap gelung, setiap satu mengandungi satu atau lebih fungsi panggil balik yang akhirnya perlu dilaksanakan pada tindanan panggilan.

Mari kita bincangkan tentang gelung acara dalam Node

  • Pertama sekali, terdapat baris gilir pemasa (secara teknikal dipanggil timbunan min), yang menyimpan data dengan setTimeout dan setIntervalfungsi panggil balik yang berkaitan.
  • Kedua, terdapat baris gilir I/O, yang mengandungi fungsi panggil balik yang berkaitan dengan semua kaedah tak segerak, seperti kaedah berkaitan yang disediakan dalam modul fs dan http.
  • Yang ketiga ialah baris gilir semakan, yang memegang fungsi panggil balik yang berkaitan dengan fungsi setImmediate, yang merupakan ciri khusus Nod.
  • Yang keempat ialah baris gilir tutup, yang menyimpan fungsi panggil balik yang dikaitkan dengan acara penutupan tugas tak segerak.

Akhir sekali, terdapat dua baris gilir berbeza membentuk baris gilir microtask. Baris gilir

  • nextTick menyimpan fungsi panggil balik yang dikaitkan dengan fungsi process.nextTick.
  • Baris gilir Promise menyimpan fungsi panggil balik yang dikaitkan dengan Promise setempat dalam JavaScript.

Perlu diambil perhatian bahawa pemasa, I/O, semak dan tutup baris gilir semuanya milik libuv. Walau bagaimanapun, kedua-dua baris gilir microtask bukan milik libuv. Walau bagaimanapun, mereka masih memainkan peranan penting dalam persekitaran masa jalan Node dan memainkan peranan penting dalam susunan panggilan balik dilaksanakan. Setelah berkata demikian, mari kita fahami cara gelung acara berfungsi.

Bagaimanakah gelung acara berfungsi?

Anak panah dalam gambar adalah petunjuk, tetapi ia mungkin tidak mudah difahami. Biar saya terangkan susunan keutamaan baris gilir. Perkara pertama yang perlu diketahui ialah semua kod JavaScript segerak yang ditulis pengguna diutamakan daripada kod tak segerak. Ini bermakna gelung peristiwa hanya berfungsi apabila timbunan panggilan kosong.

Dalam gelung acara, susunan pelaksanaan mengikut peraturan tertentu. Masih terdapat beberapa peraturan yang perlu dikuasai Mari kita lihat satu persatu:

  1. Laksanakan semua fungsi panggil balik dalam baris gilir microtask. Mula-mula tugasan dalam baris gilir nextTick, kemudian tugasan dalam baris gilir Janji.
  2. Laksanakan semua fungsi panggil balik dalam baris gilir pemasa.
  3. Jika terdapat fungsi panggil balik dalam baris gilir microtask, semua fungsi panggil balik dalam baris gilir microtask akan dilaksanakan selepas setiap fungsi panggil balik dilaksanakan dalam baris gilir pemasa. Mula-mula tugasan dalam baris gilir nextTick, kemudian tugasan dalam baris gilir Janji.
  4. Laksanakan semua fungsi panggil balik dalam baris gilir I/O.
  5. Jika terdapat fungsi panggil balik dalam baris gilir microtask, semua fungsi panggil balik dalam baris gilir microtask akan dilaksanakan secara berurutan dalam susunan baris gilir nextTick dan kemudian baris gilir Janji.
  6. Laksanakan semua fungsi panggil balik dalam baris gilir semakan.
  7. Jika terdapat fungsi panggil balik dalam baris gilir microtask, semua fungsi panggil balik dalam baris gilir microtask akan dilaksanakan selepas menyemak setiap panggilan balik dalam baris gilir. Mula-mula tugasan dalam baris gilir nextTick, kemudian tugasan dalam baris gilir Janji.
  8. Laksanakan semua fungsi panggil balik dalam baris gilir tutup.
  9. Pada penghujung gelung yang sama, laksanakan baris gilir microtask sekali lagi. Mula-mula tugasan dalam baris gilir nextTick, kemudian tugasan dalam baris gilir Janji.

Pada masa ini, jika terdapat lebih banyak panggilan balik untuk diproses, gelung acara akan berjalan semula (Anotasi: Gelung acara terus berjalan semasa program sedang berjalan dan tiada tugas untuk diproses di Seterusnya, ia akan berada dalam keadaan menunggu dan akan dilaksanakan sebaik sahaja terdapat tugasan baharu) dan ulangi langkah yang sama. Sebaliknya, jika semua panggilan balik telah dilaksanakan dan tiada lagi kod untuk diproses, gelung acara akan keluar.

Inilah yang dilakukan oleh gelung peristiwa libuv untuk melaksanakan kod tak segerak dalam Node.js. Dengan peraturan ini di tangan, kami boleh menyemak semula soalan yang kami ajukan sebelum ini.


Apabila tugas tak segerak selesai dalam libuv, bilakah Node menjalankan fungsi panggil balik yang berkaitan pada tindanan panggilan?

Jawapan: Fungsi panggil balik hanya dilaksanakan apabila timbunan panggilan kosong.

Adakah Node akan menunggu timbunan panggilan kosong sebelum menjalankan fungsi panggil balik? Atau mengganggu aliran pelaksanaan biasa untuk menjalankan fungsi panggil balik?

Jawapan: Jalankan fungsi panggil balik tanpa mengganggu aliran biasa pelaksanaan.

Kaedah seperti setTimeout dan setInterval yang melambatkan pelaksanaan fungsi panggil balik, bilakah mereka melaksanakan fungsi panggil balik?

Jawapan: Keutamaan pertama antara semua fungsi panggil balik setTimeout dan setInterval dilaksanakan (tanpa mengira baris gilir microtask).

Jika dua tugas tak segerak (seperti setTimeout dan readFile) selesai pada masa yang sama, bagaimana Node menentukan fungsi panggil balik yang dilaksanakan dahulu dalam timbunan panggilan? Adakah satu akan mempunyai keutamaan yang lebih tinggi daripada yang lain?

Jawapan: Dalam kes penyiapan serentak, panggilan balik pemasa akan dilaksanakan sebelum panggilan balik I/O.


Banyak yang telah kami pelajari setakat ini, tetapi saya harap anda boleh mengingati urutan pelaksanaan yang ditunjukkan dalam gambar di bawah, kerana ia menunjukkan sepenuhnya perkara yang dilakukan Node.js di sebalik tabir. Bagaimana untuk melaksanakan kod tak segerak.

Mari kita bincangkan tentang gelung acara dalam Node

Tetapi, anda mungkin bertanya: "Di manakah kod untuk mengesahkan visualisasi ini?". Nah, setiap baris gilir dalam gelung acara mempunyai nuansa pelaksanaan, jadi lebih baik kita membincangkannya satu demi satu. Artikel ini ialah yang pertama dalam siri tentang gelung acara Node.js. Sila pastikan anda menyemak pautan di penghujung artikel untuk memahami butiran operasi dalam setiap baris gilir Walaupun anda mempunyai kesan mendalam dalam fikiran anda sekarang, anda mungkin masih terjebak apabila anda sampai ke senario tertentu. .

Kesimpulan

Panduan visual ini merangkumi asas pengaturcaraan tak segerak dalam JavaScript, masa jalan Node.js dan libuv, yang mengendalikan operasi tak segerak. Dengan pengetahuan ini, anda boleh membina model gelung peristiwa yang berkuasa yang akan mendapat manfaat apabila menulis kod yang mengambil kesempatan daripada sifat tak segerak Node.js.

Untuk lebih banyak pengetahuan berkaitan nod, sila lawati: tutorial nodejs!

Atas ialah kandungan terperinci Mari kita bincangkan tentang gelung acara dalam Node. 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