NodeJS是近年來比較火的服務端JS平臺,這一方面得益於其在後端處理高併發的卓越性能,另外一方面在nodeJS平臺上的npm、grunt、express等強大的代碼與項目管理應用崛起,幾乎從新定義了前端的工做方式和流程。前端
NodeJS的成功標誌着它的強大,可是不是全部狀況都適合應用NodeJS做爲服務器端平臺呢?node
答案固然是否認的,而網上也是衆說紛紜。那咱們從原理出發了解一下NodeJS的適用狀況。數據庫
在講NodeJS以前咱們不仿先看一下傳統(以Apache爲表明)的服務器端處理平臺處理併發的方式。express
1. Apache的多線程高併發模式npm
Apache是當前世界排名第一的Web服務端軟件,它因爲支持多線程併發而受到廣大服務器技術選型者的歡迎。但發展到後來,Apache在一些WEB的大型應用中也漸漸暴露出它的缺點:阻塞。後端
那有的同窗會奇怪,Apache不是多線程處理併發嗎,爲何還會出現阻塞呢?服務器
要明白這一點咱們首先須要瞭解線程這個概念網絡
1.1 什麼是線程?多線程
咱們引用官方的解釋:線程能夠獨立運行的最小的CPU單位,能夠在同一個進程裏併發運行,共享該進程下的內存地址空間(注意這個特色)。併發
咱們能夠看到同一個進程下的線程是會共享相同的文件和內存的(內存地址空間),因此你們能夠想象,當不一樣的線程須要佔用同一個變量時,根據先到先得的原則,先到的線程在運做時,後來的線程只能在旁邊等待,也就是加入到了阻塞排隊序列。因此這就是形成線程阻塞的緣由。
所以,雖然說進程能夠支持多個線程,它們看似同時執行,但互相之間並不一樣步。一個進程中的多個線程共享相同的內存地址空間,這就意味着它們能夠訪問相同的變量和對象,並且它們從同一堆中分配對象。儘管這讓線程之間共享信息變得更容易,由於程序設計者必須當心,確保它們不會妨礙同一進程裏的其它線程。
瞭解了多線程並行的缺陷後,咱們就能夠更好地理解NodeJS的強大所在了。由於NodeJS是異步單線程的!
2. NodeJS的異步I/O原理
咱們先來看一段Apache請求數據庫的代碼:
代碼執行到第一行的時候線程會阻塞,等待query返回結果,而後繼續處理。因爲數據庫查詢、磁盤讀寫、網絡通訊等緣由(所謂的I/O)阻塞時間會很是大(相對於CPU始終頻率)。對於高併發的訪問,一方面線程長期阻塞等待,另外一方面爲了應付新情求而不斷添加新線程,會浪費大量系統資源,同時線程的增長也會也會佔用大量的CPU時間來處理內存上下文切換。看看node.js怎麼處理。
看到沒,就四個字:異步回調。query的第二個參數是一個回調函數,進程執行到db.query的時候不會等待結果返回,而是直接繼續執行下面的語句,直到進入事件循環。當數據庫執行結果返回的時候會將事件發送到事件隊列,等到線程進入事件循環後纔會調用以前的回調函數。更專業的說法是異步I/O。只要單線程就能夠。
那爲何NodeJS作到單線程,卻能夠實現異步呢?在這裏咱們先上一幅圖,直戳圖中的Event queue
看到沒,NodeJS的工做原理其實就是事件循環。能夠說每一條NodeJS的邏輯都是寫在回調函數裏面的,而回調函數都是有返回以後才異步執行的!
看到這裏,你不由會驚歎,NodeJS若是全部處理都異步,豈不是曉得飛了?錯錯錯!固然不是,不要忘記,NodeJS實現這些的基礎是單線程。沒錯,單線程!一條線程扛起全部操做!
你能夠想象一下,NodeJS在寒風中面對着10萬併發大軍,OK,沒問題,上來敵人一個扔到城裏,上來一個又扔到城裏。城裏全民皆兵,能夠很好地消化這些敵人。但若是上來一個相似於張飛趙雲這樣的人物,老Node內心一慘,和張飛大戰300回合,把他打殘了,再扔到城裏。那後面的10萬大軍就得等這300回合。。。
因此這說明什麼?說明NodeJS不是沒有阻塞,而是阻塞不發生在後續回調的流程,而會發生在NodeJS自己對邏輯的計算和處理。咱們已經知道,NodeJS的分發能力無比強大,能夠循環事件進行異步回調。但若是在循環事件時遇到複雜的邏輯運算,那麼單薄的單線程怎麼支撐得起上百萬的邏輯+併發呢?NodeJS它的全部I/O、網絡通訊等比較耗時的操做,均可以交給worker threads執行再回調,因此很快。但CPU的正常操做,它就只能本身抗了。
說到這裏,各位對NodeJS的特性估計也大概有個譜了。因此說適用的場景基本是呼之欲出了~!
3. NodeJS的應用場景
既然NodeJS處理併發的能力強,但處理計算和邏輯的能力反而很弱,所以,若是咱們把複雜的邏輯運算都搬到前端(客戶端)完成,而NodeJS只須要提供異步I/O,這樣就能夠實現對高併發的高性能處理。狀況就不少啦,好比:RESTFUL API、實時聊天、客戶端邏輯強大的單頁APP,具體的例子好比說:本地化的在線音樂應用,本地化的在線搜索應用,本地化的在線APP等。
順便提一下Apache,打壓了這麼多,給顆甜棗。Apache因爲其多線程高併發共享內存地址空間的特性,那就意味着若是服務器足夠強大,處理器足夠高核,Apache的運做將會很是良好,因此適用於(併發)異步處理相對較少,後臺計算量大,後臺業務邏輯複雜的應用程序。