Node.js® is a JavaScript runtime built on Chrome's V8 JavaScript engine. Node.js uses an event-driven, non-blocking I/O model that makes it lightweight and efficient.javascript
咱們來到Node的官方網站的時候就能看到這麼一句話,這句話體現了node的幾大特色,咱們來一一細看。前端
咱們學習一個東西,首先咱們要知道這東西是用來幹什麼的。之前我據說node的時候覺得nodejs是一個框架,當了解到node以後就認爲這只是在服務端的javascript,可是事實的真相是這樣的麼?咱們來看一看上面這段話。Node.js是一個構建在Chrome的V8引擎上的javascript的運行時,可能你不太能理解運行時是什麼,其實在個人理解中就和Java的JRE(Java Runtime Environment)是差很少的,他提供了API環境、運行環境,讓咱們的js在服務端能夠跑起來,同時提供了能夠對文件系統、網絡等等進行操做的api,這是讓前端工程師無比興奮的突破。java
接下來的這句話體現了Node的幾大特性:node
再說上面的幾個特性以前,咱們先來看一看,在我學習的途中常常會看到有人說Node在處理高併發、I/O密集型服務是具備優點的,那麼個人疑問是I/O密集型是啥,搜索資料後發現,跟I/O密集相對應的是CPU密集,咱們能夠看一看這二者之間的區別。web
好了咱們看完這二者之間的區別,咱們也就能瞭解,爲啥Node適合web開發,你想想咱們在進行web開發的時候,咱們進行的都是些什麼操做,靜態資源讀取、網絡操做、數據庫的增刪改查,咱們能夠發現web場景中I/O操做是最耗時的操做。如今CPU的提速咱們執行指令的速度是很快的,可是咱們進行I/O操做仍是很是耗時的。咱們能夠看到web是一個很典型的I/O密集型服務,那麼咱們爲何說Node就很是適合web場景呢?咱們等會兒再談。ajax
下面咱們來看一看高併發的狀況,在《深刻淺出NodeJS》這本書中咱們能看到樸靈老師對服務模型的看法,我以爲很能說明問題,咱們一塊兒來看一看:數據庫
石器時代:同步
在好久好久之前,咱們服務器是同步的,一次只能服務一個請求,就好比說咱們一個飯店,請了一個廚子一個服務員,咱們如今只有一個廚子,因此咱們如今只能接收一個客人的點餐,等上個客人的作好了咱們才能繼續進行下面一位客人的點餐,咱們都知道這樣的效率確定是不行的,因此又有了下面的演進。api
青銅時代:複製進程
咱們能夠經過進程的複製,一個進程服務一個請求,這樣咱們就可以服務多個請求了,可是夢想是很美好的,理想很豐滿。繼續用上面的例子,咱們飯店大起來了,一個廚子這樣已經忙不過來了,這時候,咱們能想到的是什麼,再多請幾個廚子,這樣也可以解決多個客人的問題,可是咱們想了一下,請這麼多廚子,工資誰發啊,太貴了。這也是複製進程的一個缺點,進程的複製是很是昂貴的,咱們要複製進程內的狀態,並且進程內還會有不少相同的狀態會形成浪費,那麼又該怎麼辦呢?服務器
白銀時代:多線程
咱們從上面的角度上來想,咱們速度慢的操做也就是讀取的操做,不須要很厲害的廚子,小廚子就好了,因而乎咱們就炒掉了大廚,用大廚的錢請了幾個小廚子,這樣咱們的小廚子也可以進行炒菜,因此咱們接到點餐以後,就給這幾個小廚子作。可是呢咱們一個服務員對應的廚子是有限的,咱們能夠想象,點菜這個操做是很是快的,可能服務員點完菜以後就開始玩了,等廚子作好了纔會端上來,這就形成了CPU的浪費,同時呢,對於多線程來講,佔用內存空間,線程的上下文切換等等問題也是沒法作到很好的知足需求。網絡
黃金時代:事件驅動
爲了解決高併發問題,基於事件驅動的服務模型就出現了,就像Node和Nginx都是基於事件驅動的,採用單線程就避免了沒必要要的內存開銷和上下文切換。看上面的例子,其實咱們僱一個服務員,排隊叫號,而後就接待下一個客人,不用等這個客人的菜好了才服務下一個,等廚子作好了菜就直接給服務員說菜作好了,而後叫號,客人來取就OK了。
借用一張老師的圖,其實這張圖其實咱們能看得很清楚,咱們JS是單線程的,node中也是這樣的,客戶端的N個請求,咱們接收到以後,是直接將耗時得操做放到了後面的線程池裏去操做,使用單線程能夠避免內存的消耗,以及上下文的切換。同時,咱們利用事件驅動,能夠在後面的線程I/O操做完成後以事件的方式通知主線程,而後返回結果。
其實說到這裏,有些人就和我同樣困惑了,不是說nodejs是單線程麼,怎麼又冒出了多線程。其實咱們想想也可以明白,若是nodejs只是靠單線程工做,那麼他怎麼完成高併發的web服務呢?咱們能夠這麼說,nodejs的單線程是針對主進程的,而異步操做、I/O操做等等都是靠操做系統底層的多線程調度了,nodejs的單線程只是負責調度,就像飯店的服務員同樣,只負責接單,作菜的都是後臺的廚師。還有就是nodejs是單線程,那麼如今的多核CPU該怎麼去使用呢?其實不用咱們擔憂,node是考慮了這樣的狀況的,nodejs是有專門的模塊來進行操做的。
那麼事件驅動又是個什麼東西呢?其實,咱們在作前端開發的時候是常常和事件打交道的,好比ajax,咱們發起一個請求,而後監聽事件,成功以後就執行回調。其實這也是node的一大特色,就像node在接收請求同樣的,node接收到請求以後,將對應的I/O操做交給操做系統,而後監聽事件,當I/O操做完成以後,觸發事件執行回調拿到數據。
阻塞I/O就是當用戶發一個讀取文件的操做的時候,進程就會被阻塞,直到要讀取的數據所有準備好返回給用戶。那非阻塞I/O呢,就是用戶發起一個讀取文件操做的時,函數當即返回,不做任何等待,進程繼續執行,當讀取操做完成以後,主進程再去拿數據。那程序如何知道要讀取的數據已經準備好了呢?最簡單的方法就是輪詢,這個在樸靈老師的書裏面也提到了幾種方式。
今天就簡單的學習了一下node,若是有什麼地方不對的請多指教,也是才學習nodejs。