nodejs 服务器怎么导入qs_nodejs基本原理总结
? ?戳藍(lán)字「前端技術(shù)優(yōu)選」關(guān)注我們哦!
一. nodejs背景
先來說說nodejs最常被提到的幾個(gè)關(guān)鍵詞,“單線程”,“非阻塞異步IO”,“事件循環(huán)”。接下來主要來通過這幾個(gè)關(guān)鍵字總結(jié)一下nodejs的內(nèi)在原理,以及引申出的一些問題。
二. nodejs是單線程嗎?
如果說nodejs是單線程語言,可以想象一下,一個(gè)單實(shí)例的nodejs的服務(wù)器同時(shí)接受100個(gè)用戶請(qǐng)求時(shí),第100個(gè)用戶的請(qǐng)求要等前面99的用戶處理完成才能得到處理,如果每個(gè)用戶的請(qǐng)求要0.3秒,第100個(gè)用戶需要30秒的等待,這顯然和我們的實(shí)際情況并不符合,所以說,nodejs并不是單純的單線程。
那為什么說nodejs是單線程語言呢?而是因?yàn)閚odejs中javascript代碼的執(zhí)行是單線程,怎么理解這句話,看下面代碼。
console.log(執(zhí)行結(jié)果:
$上面的代碼中,setTimeout的回調(diào)代碼在while執(zhí)行4秒期間,計(jì)時(shí)器已經(jīng)是過了兩秒的,而'javascript setTimeout'這一句打印卻在'javascript end'之后,即使計(jì)時(shí)器在兩秒后回調(diào)代碼應(yīng)該被執(zhí)行時(shí),因?yàn)閖avascript的線程處于非空閑狀態(tài),而不能輸出'javascript setTimeout',javascript代碼是單線程這樣理解。
三. nodejs的異步IO
再拿上面的例子來看,當(dāng)100個(gè)用戶請(qǐng)求同時(shí)被接受到時(shí),當(dāng)需要IO(網(wǎng)絡(luò)IO/文件IO)操作時(shí),單線程的javascript并不會(huì)停下來等待IO操作完成,而是“事件驅(qū)動(dòng)”開始介入,javascript執(zhí)行線程繼續(xù)執(zhí)行未完的javascript代碼,當(dāng)執(zhí)行完成后該線程處于空閑狀態(tài),可以看下面這一段代碼示例。
// http.js// req.jsnode http.js // 啟動(dòng)服務(wù)器node req.js // 發(fā)起100個(gè)請(qǐng)求
可以看出100個(gè)請(qǐng)求均是在請(qǐng)求返回之前非常短的時(shí)間都被得到了處理,而返回則均在請(qǐng)求之后,并非請(qǐng)求按接收順序依次等待各個(gè)IO得到處理后依次返回。
四. 事件循環(huán)
說到事件循環(huán),在上面的請(qǐng)求中,100個(gè)請(qǐng)求的都在非常短的時(shí)間得到了處理,而后請(qǐng)求又各自得到了回復(fù),可以思考一下,javascript已經(jīng)執(zhí)行到了第100個(gè)請(qǐng)求,而第1個(gè)請(qǐng)求才得到回復(fù),而第一個(gè)請(qǐng)求的棧信息沒有丟失,說明第一個(gè)請(qǐng)求的請(qǐng)求棧信息被記錄了,這一過程便是注冊(cè)IO事件。
從上面注冊(cè)事件后,事件循環(huán)得到激活,對(duì)于上面代碼中fs.readFile這個(gè)讀文件IO則開始真正執(zhí)行,而這時(shí)候IO的執(zhí)行跟javascript代碼的執(zhí)行便沒有關(guān)系了,由nodejs底層libuv提供的線程池接收該文件IO執(zhí)行工作,該線程池默認(rèn)大小為4,可以通過環(huán)境變量process.env.UV_THREADPOOL_SIZE在啟動(dòng)的時(shí)候進(jìn)行調(diào)整,但是最大不能超過1024個(gè),有興趣的可以查看線程池源碼;由上可以看出nodejs內(nèi)部實(shí)際是多進(jìn)程并行工作的,而是利用事件循環(huán)做了封口處理。
再來說說事件循環(huán),上面示例中fs.readFile讀文件時(shí),如何知道這個(gè)讀操作完成了呢?可以思考一下,讀操作是線程池來控制執(zhí)行的,在該線程執(zhí)行前,先在注冊(cè)事件的內(nèi)存中初始化一個(gè)狀態(tài)是“執(zhí)行中”,并且事件循環(huán)也已經(jīng)被激活,開始輪詢等待執(zhí)行結(jié)果,當(dāng)執(zhí)行IO的線程在執(zhí)行完之后,再通過底層的異步IO接口(epoll_wait/IOCP)進(jìn)行通知到初始注冊(cè)的任務(wù)隊(duì)列內(nèi)存進(jìn)行變更狀態(tài),事件循環(huán)輪詢到狀態(tài)變成“已完成”,這時(shí)候在IO事件注冊(cè)時(shí)注入的回調(diào)函數(shù)得到執(zhí)行權(quán),javascript線程開始工作,整個(gè)異步過程完畢。
可以看看事件循環(huán)里面都要經(jīng)過哪些步驟,如何稱為事件循環(huán)。
可以看一下英文原版的解釋,事件循環(huán)解釋
翻譯過來:
**階段概覽**timers:這個(gè)階段執(zhí)行setTimeout() 和 setInterval()中到期的回調(diào)函數(shù)
I/O callbacks:執(zhí)行所有除了setTimeout() ,setInterval(),close事件,setImmediate的其他回調(diào)函數(shù)
idle, prepare:僅內(nèi)部使用
poll:獲取新的I/O 事件,在適當(dāng)?shù)臈l件下nodejs會(huì)阻塞在這個(gè)階段
check:setImmediate的回調(diào)函數(shù)在這里被調(diào)用
close callbacks:像socket.on("close",func)這一類執(zhí)行close事件的回調(diào)
如上內(nèi)容均為自己總結(jié),難免會(huì)有錯(cuò)誤或者認(rèn)識(shí)偏差,如有問題,希望大家留言指正,以免誤人,若有什么問題請(qǐng)留言,會(huì)盡力回答之。如果對(duì)你有幫助不要忘了分享給你的朋友或者點(diǎn)擊右下方的“在看”哦!也可以關(guān)注作者,查看歷史文章并且關(guān)注最新動(dòng)態(tài),助你早日成為一名全棧工程師!
總結(jié)
以上是生活随笔為你收集整理的nodejs 服务器怎么导入qs_nodejs基本原理总结的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 组合筛选vue_Vue 3 组合式API
- 下一篇: z390 黑苹果启动盘_不到800元买块