Artikel ini ialah beberapa pemahaman peribadi tentang nodejs dalam pembangunan dan pembelajaran sebenar Ia kini disusun untuk rujukan masa hadapan.
I/O: Input / Output, input dan output sistem.
Sistem boleh difahami sebagai individu, seperti seseorang Apabila anda bercakap, ia adalah output, dan apabila anda mendengar, ia adalah input.
Perbezaan antara menyekat I/O dan tidak menyekat I/O terletak pada sama ada sistem boleh menerima input lain dalam tempoh dari input ke output.
Berikut ialah dua contoh untuk menggambarkan apa itu menyekat I/O dan tidak menyekat I/O:
1 >
Mula-mula kita perlu menentukan skop sistem Dalam contoh ini, makcik kantin dan pelayan di restoran dianggap sebagai sistemInput sedang memesan, dan output sedang dihidangkan makanan.
Kemudian sama ada anda boleh menerima pesanan orang lain antara memesan dan menghidangkan makanan, anda boleh menentukan sama ada ia menyekat I/O atau tidak menyekat I/O. Makcik kafeteria pula, apabila dia sedang menempah, dia tidak boleh memesan untuk pelajar lain hanya selepas pelajar itu selesai memesan dan menghidangkan hidangan, barulah dia boleh menerima tempahan pelajar seterusnya, jadi makcik kafeteria sedang Menghalang. I/O.
Untuk pelayan restoran, dia boleh melayan tetamu seterusnya selepas membuat pesanan dan sebelum tetamu menghidangkan hidangan, jadi pelayan mempunyai I/O yang tidak menghalang.
2. Buat kerja rumahBila basuh baju, tak perlu tunggu dekat mesin basuh pergi ke sana pada masa ini Sapu lantai dan mengemas meja Apabila meja dikemas dan pakaian dicuci, gantung pakaian untuk mengeringkan Ia hanya mengambil masa 25 minit.
Mencuci sebenarnya adalah I/O yang tidak menyekat Anda boleh melakukan perkara lain antara memasukkan pakaian ke dalam mesin basuh dan menyelesaikan pembasuhan.
Sebab I/O yang tidak menyekat boleh meningkatkan prestasi ialah ia boleh menjimatkan menunggu yang tidak perlu.Kunci untuk memahami I/O tidak menyekat ialah :
Tentukan sempadan sistem untuk I/O
. Ini sangat kritikal jika sistem diperluaskan, seperti contoh restoran di atas, jika sistem diperluaskan ke seluruh restoran, maka chef pasti akan menjadi I/O yang menyekat.. Jika gambar rajah seni bina di bawah dibahagikan mengikut penyelenggaraan benang, garis putus-putus di sebelah kiri ialah benang nodejs dan garis putus-putus di sebelah kanan ialah benang c.
Sekarang benang nodejs perlu menanyakan pangkalan data Ini adalah operasi I/O biasa Ia tidak akan menunggu hasil I/O dan terus memproses operasi lain Ia akan mengagihkan sejumlah besar kuasa pengkomputeran kepada benang c lain untuk pengiraan.Tunggu sehingga keputusan keluar dan kembalikan ke utas nodejs Sebelum mendapat keputusan, utas nodejs juga boleh melakukan operasi I/O lain, jadi ia tidak menyekat.
benang nodejsbersamaan dengan bahagian kiri sebagai pelayan dan benang c sebagai tukang masak.
Jadi, I/O tidak menyekat nod diselesaikan dengan memanggil urutan pekerja c.
Bagaimana untuk memberitahu benang nodejs apabila benang c memperoleh hasilnya? Jawapannya ialah didorong peristiwa.
Didorong peristiwa
Tidak menyekat: Fungsi kembali serta-merta semasa I/O, dan proses tidak menunggu I/O selesai.
Kemudian bagaimana untuk mengetahui hasil yang dikembalikan, anda perlu menggunakan event driven.
Apa yang dipanggil event-driven boleh difahamkan sama seperti acara klik hadapan saya mula-mula menulis acara klik, tetapi saya tidak tahu bila ia akan berlaku dicetuskan. Saya hanya membiarkan utas utama melaksanakan acara apabila ia dicetuskan.
Mod ini juga merupakan mod pemerhati, iaitu, saya mula-mula mendengar acara, dan kemudian melaksanakannya apabila ia dicetuskan. Jadi bagaimana untuk melaksanakan pemacu acara? Jawapannya ialah
Asynchronous Programming.
Pengaturcaraan Asynchronous
glob(__dirname+'/**/*', (err, res) => { result = res console.log('get result') })
Parameter pertama fungsi panggil balik nodejs ialah ralat, dan parameter seterusnya ialah hasilnya. Mengapa melakukan ini?
try { interview(function () { console.log('smile') }) } catch(err) { console.log('cry', err) } function interview(callback) { setTimeout(() => { if(Math.random() <p>Selepas pelaksanaan, ia tidak ditangkap dan ralat telah dilemparkan secara global, menyebabkan keseluruhan program nodejs ranap. </p><p><img src="https://img.php.cn/upload/image/244/886/980/1657110712466688.png" title="1657110712466688.png" alt="Ringkasan dan perkongsian untuk memahami beberapa nod utama nodej"></p><p> tidak ditangkap oleh try catch kerana setTimeout membuka semula gelung peristiwa Setiap kali gelung peristiwa dibuka, konteks tindanan panggilan dijana semula gelung. Apabila fungsi panggil balik setTimeout dilaksanakan, timbunan panggilan adalah berbeza. Untuk butiran, sila rujuk artikel ini <a href="https://juejin.cn/post/6995749646366670855" target="_blank" title="https://juejin.cn/post/6995749646366670855"> Masalah apabila menggunakan baris gilir tak segerak untuk cuba tangkap </a>. </p><p>Jadi apa yang perlu kita lakukan? Gunakan ralat sebagai parameter: </p><pre class="brush:php;toolbar:false">function interview(callback) { setTimeout(() => { if(Math.random() <p>Tetapi ini lebih menyusahkan, dan ia perlu dinilai dalam panggilan balik, jadi konvensyen matang dibuat jika ia tidak wujud , ia bermakna Pelaksanaan berjaya. </p><pre class="brush:php;toolbar:false">function interview(callback) { setTimeout(() => { if(Math.random() <h3 data-id="heading-5"><strong>Kawalan proses tak segerak</strong></h3><p>Kaedah penulisan panggil balik nodejs bukan sahaja akan membawa kawasan panggil balik, tetapi juga membawa soalan <strong>kawalan proses tak segerak</strong> . </p><p>Kawalan proses tak segerak terutamanya merujuk kepada cara mengendalikan logik konkurensi apabila konkurensi berlaku. Masih menggunakan contoh di atas, jika rakan sekerja anda menemuduga dua syarikat, dia tidak akan ditemuduga oleh syarikat ketiga sehingga dia berjaya menemuduga dua syarikat. Jadi bagaimana untuk menulis logik ini? Ia adalah perlu untuk menyokong setiap kiraan pembolehubah secara global: </p><pre class="brush:php;toolbar:false">var count = 0 interview((err) => { if (err) { return } count++ if (count >= 2) { // 处理逻辑 } }) interview((err) => { if (err) { return } count++ if (count >= 2) { // 处理逻辑 } })
Menulis seperti di atas sangat menyusahkan dan hodoh. Oleh itu, kaedah penulisan janji dan async/menunggu muncul kemudian.
Gelung peristiwa semasa tidak boleh mendapatkan hasil, tetapi gelung acara masa hadapan akan memberikan hasil kepada anda. Ia sangat serupa dengan apa yang akan dikatakan oleh seorang bajingan.
janji bukan sahaja sampah, tetapi juga mesin negara:
const pro = new Promise((resolve, reject) => { setTimeout(() => { resolve('2') }, 200) }) console.log(pro) // 打印:Promise { <pending> }</pending>
Melaksanakan kemudian atau menangkap akan mengembalikan janji baharu Keadaan akhir janji ditentukan oleh hasil pelaksanaan fungsi panggil balik daripada kemudian dan tangkap :
function interview() { return new Promise((resolve, reject) => { setTimeout(() => { if (Math.random() > 0.5) { resolve('success') } else { reject(new Error('fail')) } }) }) } var promise = interview() var promise1 = promise.then(() => { return new Promise((resolve, reject) => { setTimeout(() => { resolve('accept') }, 400) }) })
Status janji1 ditentukan oleh status janji sebagai balasan, iaitu status janji1 selepas janji sebagai balasan dilaksanakan. Apakah faedah ini? Ini boleh menyelesaikan masalah neraka panggil balik.
var promise = interview() .then(() => { return interview() }) .then(() => { return interview() }) .then(() => { return interview() }) .catch(e => { console.log(e) })
kemudian Jika status janji yang dikembalikan itu ditolak, maka tangkapan pertama akan dipanggil, dan yang berikutnya tidak akan dipanggil. Ingat: menolak panggilan tangkapan pertama, dan menyelesaikan panggilan pertama kemudian.
Jika janji hanya untuk menyelesaikan panggilan balik neraka, ia adalah terlalu kecil untuk meremehkan janji Fungsi utama janji adalah untuk menyelesaikan proses tak segerak masalah kawalan. Jika anda ingin menemu bual dua syarikat pada masa yang sama:
function interview() { return new Promise((resolve, reject) => { setTimeout(() => { if (Math.random() > 0.5) { resolve('success') } else { reject(new Error('fail')) } }) }) } promise .all([interview(), interview()]) .then(() => { console.log('smile') }) // 如果有一家公司rejected,就catch .catch(() => { console.log('cry') })
Apakah sebenarnya penyegerakan/menunggu:
console.log(async function() { return 4 }) console.log(function() { return new Promise((resolve, reject) => { resolve(4) }) })
Cetak Hasilnya adalah sama iaitu async/wait hanyalah syntactic sugar for promise.
Kami tahu bahawa cuba tangkap menangkap ralat bergantung pada tindanan panggilan dan hanya boleh menangkap ralat di atas tindanan panggilan. Tetapi jika anda menggunakan await, anda boleh menangkap ralat dalam semua fungsi dalam timbunan panggilan. Walaupun ralat dilemparkan dalam timbunan panggilan gelung acara lain, seperti setTimeout.
Ubah suai kod temu duga dan anda boleh melihat bahawa kod itu lebih diperkemas.
try { await interview(1) await interview(2) await interview(2) } catch(e => { console.log(e) })
Bagaimana jika ia adalah tugasan yang selari?
await Promise.all([interview(1), interview(2)])
Oleh kerana I/0 nodej yang tidak menyekat, adalah perlu untuk menggunakan kaedah dipacu peristiwa untuk mendapatkan I/ Hasil O dan laksanakan pemerolehan dipacu peristiwa Pengaturcaraan tak segerak, seperti fungsi panggil balik, mesti digunakan untuk mendapatkan hasilnya. Jadi bagaimana untuk melaksanakan fungsi panggil balik ini untuk mendapatkan hasilnya? Kemudian anda perlu menggunakan gelung acara.
Gelung peristiwa ialah asas utama untuk merealisasikan fungsi I/O tidak menyekat nodej dan gelung peristiwa adalah kedua-dua keupayaan yang disediakan oleh perpustakaan libuv
.
代码演示:
const eventloop = { queue: [], loop() { while(this.queue.length) { const callback = this.queue.shift() callback() } setTimeout(this.loop.bind(this), 50) }, add(callback) { this.queue.push(callback) } } eventloop.loop() setTimeout(() => { eventloop.add(() => { console.log('1') }) }, 500) setTimeout(() => { eventloop.add(() => { console.log('2') }) }, 800)
setTimeout(this.loop.bind(this), 50)
保证了50ms就会去看队列中是否有回调,如果有就去执行。这样就形成了一个事件循环。
当然实际的事件要复杂的多,队列也不止一个,比如有一个文件操作对列,一个时间对列。
const eventloop = { queue: [], fsQueue: [], timerQueue: [], loop() { while(this.queue.length) { const callback = this.queue.shift() callback() } this.fsQueue.forEach(callback => { if (done) { callback() } }) setTimeout(this.loop.bind(this), 50) }, add(callback) { this.queue.push(callback) } }
首先我们弄清楚了什么是非阻塞I/O,即遇到I/O立刻跳过执行后面的任务,不会等待I/O的结果。当I/O处理好了之后就会调用我们注册的事件处理函数,这就叫事件驱动。实现事件驱动就必须要用异步编程,异步编程是nodejs中最重要的环节,它从回调函数到promise,最后到async/await(使用同步的方法写异步逻辑)。
更多node相关知识,请访问:nodejs 教程!
Atas ialah kandungan terperinci Ringkasan dan perkongsian untuk memahami beberapa nod utama nodej. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!