Node.js是讓Javascript脫離瀏覽器運行在服務器的一個平臺(或者叫框架),不是語言;運行在瀏覽器外不用考慮頭疼的Javascript兼容性問題採用單線程、異步IO與事件驅動的設計來實現高併發(異步事件也在必定程度上增長了開發和調試的難度);Node.js內建一個HTTP服務器,因此對於網站開發來講是一個好消息;node
事實上,在實現 Node.js 之初,做者 Ryan Dahl 並無選擇 JavaScript,他嘗試過 C、Lua,皆因其欠缺一些高級語言的特性,如閉包、函數式編程,導致程序複雜,難以維護。而 JavaScript 則是支持函數式編程範型的語言,很好地契合了 Node.js 基於事件驅動的編程模型。加之 Google 提供的 V8 引擎,使 JavaScript 語言的執行速度大大提升。最終呈如今咱們面前的就成了 Node.js,而不是 Node.c,Node.lua 或其餘語言的實現。c++
nodejs不是一個Javascript應用,而是一個用c++語言編寫的一個JavaScript運行環境,Node.js採用的Google Chrome瀏覽器V8引擎,性能很好;同時還提供了許多系統級的API,好比像文件操做,網絡編程等。瀏覽器端的Javascript代碼在運行時會受到各類安全性的限制,對客戶系統的操做有限。相比之下,Node.js則是一個全面的後臺運行時,爲Javascript提供了其餘語言可以實現的許多功能。編程
Node.js在設計上也是比較創新,它以單進程,單線程模式運行(這和Javascript的運行方式是一致的),事件驅動機制是Node.js經過內部單線程高效率地維護事件循環隊列來實現的,沒有多線程的資源佔用和上下文切換,這意味着面對大規模的http請求,Node.js憑藉事件驅動搞定一切,習慣了傳統語言的網絡服務開發人員可能對多線程併發和協做很是熟悉,可是面對Node.js,咱們須要接受和理解它的特色。瀏覽器
Node.js的首要目標是提供一種簡單的、用於建立高性能服務器的開發工具,而且在該服務器中科院運行各類應用程序。安全
如今讓咱們來看一下如今流行的服務器端語言中存在着什麼問題。在Java、PHP、ASP.NET等語言中,都會爲一個客戶端鏈接建立一個新的線程,而每一個線程大約要消耗2MB的內存,也就是說理論上,擁有8G內存的服務器可以同時支持的鏈接數爲4000個左右。要讓Web應用程序支持更多的用戶,就須要相應增長服務器數量,這直接致使了Web應用程序的硬件成本上升。
Node.js改變了客戶端到服務器端的鏈接方法,從而解決了上述的問題。Node.js並不爲每一個客戶端鏈接建立新的線程,而是爲每一個客戶端鏈接觸發一個在Node.js內部進行處理的事件(這就是node.js爲何叫作事件驅動的緣由)。因此,node.js能夠經過這一特性,同時處理多達幾萬個用戶的客戶端鏈接。服務器
首先要弄明白是什麼阻塞型I/O和非阻塞型I/O,才能繼續咱們的話題:網絡
阻塞I/O多線程
程序執行過程當中必然要進行不少I/O操做,讀寫文件、輸入輸出、請求響應等等。I/O操做時最費時的,至少相對於代碼來講,在傳統的編程模式中,舉個例子,你要讀一個文件,整個線程都暫停下來,等待文件讀完後繼續執行。換言之,I/O操做阻塞了代碼的執行,極大地下降了程序的效率。閉包
非阻塞I/O 併發
理解了阻塞I/O,非阻塞I/O就好理解。非阻塞I/O是程序執行過程當中,I/O操做不會阻塞程序的執行,也就是在I/O操做的同時,繼續執行其餘代碼(這得益於Node的事件循環機制)。在I/O設備效率還遠遠低於CPU效率的時代,這種I/O模型(非阻塞I/O)爲程序帶來的性能上的提升是很是可觀的。
咱們能夠這樣理解,在Node中,除了代碼,一切都是並行的!
接下來咱們來看看什麼是事件環機制或者叫事件輪詢(event loop)。
Event Loop 是一個很重要的概念,指的是計算機系統的一種運行機制。
想要理解Event Loop,就要從程序的運行模式講起。運行之後的程序叫作進程(Process),通常狀況下,一個進程一次只能執行一個任務。
若是有不少任務須要執行,不外乎三種解決方法。
(1),排隊。由於一個進程一次只能執行一個任務,只好等前面的任務執行完了,再執行後面的任務。
(2),新建進程。使用fork命令,爲每一個任務新建一個進程。
(3),新建線程。由於進程太耗費資源,因此現在的程序每每容許一個進程包含多個線程,由線程去完成任務。
以JavaScript語言爲例,它是一種單線程語言,全部任務都在一個線程上完成,即採用上面的第一種方法。一旦遇到大量任務或者遇到一個耗時的任務,網頁就會出現"假死",由於JavaScript停不下來,也就沒法響應用戶的行爲。
你也許會問,JavaScript爲何是單線程,難道不能實現爲多線程嗎?
這跟歷史有關係:
JavaScript語言的一大特色就是單線程,也就是說,同一個時間只能作一件事。那麼,爲何JavaScript不能有多個線程呢?這樣能提升效率啊。
JavaScript的單線程,與它的用途有關。做爲瀏覽器腳本語言,JavaScript的主要用途是與用戶互動,以及操做DOM。這決定了它只能是單線程,不然會帶來很複雜的同步問題。
好比,假定JavaScript同時有兩個線程,一個線程在某個DOM節點上添加內容,另外一個線程刪除了這個節點,這時瀏覽器應該以哪一個線程爲準?
因此,爲了不復雜性,從一誕生,JavaScript就是單線程,這已經成了這門語言的核心特徵,未來也不會改變。
爲了利用多核CPU的計算能力,HTML5提出Web Worker標準,容許JavaScript腳本建立多個線程,可是子線程徹底受主線程控制,且不得操做DOM。
因此,這個新標準並無改變JavaScript單線程的本質。
回到EventLoop:
單線程就意味着,全部任務須要排隊,前一個任務結束,纔會執行後一個任務。若是前一個任務耗時很長,後一個任務就不得不一直等着。
若是排隊是由於計算量大,CPU忙不過來,倒也算了,可是不少時候CPU是閒着的,由於IO設備(輸入輸出設備)很慢(好比Ajax操做從網絡讀取數據),不得不等着結果出來,再往下執行。
JavaScript語言的設計者意識到,這時主線程徹底能夠無論IO設備,掛起處於等待中的任務,先運行排在後面的任務。等到IO設備返回告終果,再回過頭,把掛起的任務繼續執行下去。
因而,全部任務能夠分紅兩種,一種是同步任務(synchronous),另外一種是異步任務(asynchronous)。同步任務指的是,在主線程上排隊執行的任務,只有前一個任務執行完畢,
才能執行後一個任務;異步任務指的是,不進入主線程、而進入"任務隊列"(task queue)的任務,只有"任務隊列"通知主線程,某個異步任務能夠執行了,該任務纔會進入主線程執行。
只要主線程空了,就會去讀取"任務隊列",這就是JavaScript的運行機制。這個過程會不斷重複。
如圖:
通過上面對node.js的瞭解,那麼node.js適合用戶開發哪一種應用呢?
答案是:當應用須要處理大量併發的輸入/輸出(I/O),而在向客戶端發出響應以前,服務器端並不須要進行很是複雜的處理,這個時候,咱們應該考慮使用node.js來開發咱們的應用。
例如: 聊天服務器 綜合服務類網站 電子商務網站等