nodejs的特色總共有如下幾點html
下面是一道很經典的面試題,描述了node的總體運行機制,相信不少人都碰到了。這道題背後的原理就是nodejs代碼執行順序java
setTimeout(function() { console.log('4'); },0) setImmediate(function() { console.log('5'); }) let s = new Promise(function(resolve, reject) { console.log('2'); resolve(true) console.log('7') }) s.then(function() { console.log('3'); }) process.nextTick(function() { console.log('6') }) console.log('1'); // 我電腦的輸出結果是 二、七、一、六、三、四、5
nodejs的運行機制: nodejs主線程主要起一個任務調度的做用。nodejs用一個主線程處理全部的請求, 將I/O操做交由底下的線程池處理;在全部主線程任務執行完成後,主線程處理事件隊列。 因此在同步初始化代碼執行完成後,nodejs會基於事件隊列不停的作事件循環。事實上,nodejs運行環境 = 主線程(單線程,包括事件隊列) + 線程池(工做線程池,執行其餘工做-多線程)node
注: 在主線程執行完和事件循環總共7個階段,每個階段執行完都會調用一遍process.nextTick
回調,一遍microtaks
(promise);git
主線程中,console.log
和promise
的new方法在初始化主線程中執行,他們倆個的輸出時間按照先上後下的順序輸出,他們兩個執行完後會當即執行主線程的process.nextTick
,而後執行promise.then
方法,而後是進入事件隊列中執行setTimeout
和setImmediate
。由於setTimeout的
'最少通過n毫秒後執行的腳本'特性,致使沒法肯定setTimeout
和setImmediate
的執行前後順序,但若是是在回調函數中,則必然setImmediate
先執行,由於事件循環的階段中,setImmediate緊挨着回調函數以後執行,而setTimeout則在下次事件循環中執行。github
IO操做: IO操做就是以流的形式,進行的操做,好比網絡請求,文件讀取寫入。IO操做也就是input和output的操做。web
阻塞IO: 在調用阻塞O時,應用程序須要等待IO完成才能返回結果。 阻塞IO的特色:調用以後必定要等到系統內核層面完成全部操做以後,調用才結束。 阻塞O形成CUP等待IO,浪費等待時間,CPU的處理能力不能獲得充分利用。面試
非阻塞IO: 爲了提升性能,內核提供了非阻塞IO,非阻塞IO跟阻塞IO的差異是調用以後會當即返回。阻塞IO完成整個獲取數據的過程,而非阻塞IO則不帶數據直接返回,要獲取數據,還要經過描述符再次讀取。非阻塞IO返回以前,node主線程能夠用來處理其餘事物,此時性能提高很是明顯。數據庫
爲何node擅長I/O密集型,不擅長CPU密集型:由於node的I/O處理中主線程只負責轉發,實際操做在其餘線程及線程隊列裏完成,因此性能相對較高; 而CPU密集則要求node的主線程處理,這時候其他請求只能等待promise
個人理解: node的異步I/O分爲兩個階段,第一個階段是主線程調用線程池裏的工做線程執行異步操做,主線程取回對應的描述符,存儲下來,工做線程執行相關操做取回數據後存儲下來,這一部分在主線程接收到請求後當即完成;第二個階段在事件隊列裏完成,根據描述符去工做線程裏去獲取數據,以提高性能.安全
如下是對nodejs高併發的理解,nodejs的高併發體如今處理I/O的性能上,而不是CPU密集上,摘錄自官網文檔
讓咱們思考這樣一種狀況:每一個對 Web 服務器的請求須要 50 毫秒完成,而那 50 毫秒中的 45 毫秒是能夠異步執行的數據庫 I/O。選擇 非阻塞 異步操做能夠釋放每一個請求的 45 毫秒來處理其它請求。僅僅是選擇使用 非阻塞 方法而不是 阻塞 方法,就是容量上的重大區別。
Node 有兩種類型的線程:一個事件循環線程和 k 個工做線程。 事件循環負責 JavaScript 回調和非阻塞 I/O,工做線程執行與 C++ 代碼對應的、完成異步請求的任務,包括阻塞 I/O 和 CPU 密集型工做。 這兩種類型的線程一次都只能處理一個活動。 若是任意一個回調或任務須要很長時間,則運行它的線程將被 阻塞。 若是你的應用程序發起阻塞的回調或任務,在好的狀況下這可能只會致使吞吐量降低(客戶端/秒),而在最壞狀況下可能會致使徹底拒絕服務。要編寫高吞吐量、防 DoS 攻擊的 web 服務,您必須確保無論在良性或惡意輸入的狀況下,您的事件循環線程和您的工做線程都不會阻塞。
一般意義上,I/O密集型活動,如網絡I/O、文件I/O,DNS操做等一般建議放在對外提供網絡服務的端口所在的服務內,剩下的諸如大內容的crypto,zlib,fs同步操做、子進程,JSON處理、計算等儘可能另起node服務或者其餘語言服務去進行,由於這些操做會影響到node的主線程的性能和安全性。
事實上,對於nodejs的相關理解更多的收穫在於這裏,nodejs官網指南的中文文檔,之前有點粗心了