6分鐘看懂 Node.js 武功精髓

半島荼靡發表於2018-11-21

版權宣告:本文已在我的公眾號 :【前端你別鬧】 ,原創首發, 歡迎關注~!轉載請務必註明出處! https://blog.csdn.net/xllily_11/article/details/84303153
閱讀大約需要6分鐘。

1、為什麼要學習Node.js?
Node.js是目前非常火熱的技術,可是作為一個前端開發人員,為什麼要學Node.js?

說Node.js優劣的文章,網上一大堆,在這兒就不過多描述了。技術是服務於業務的,學技術最終目的就是為了更高的收入,我們們就是這麼俗,那就從以下兩點來看看,為什麼要學Node.js

從工作上來說

首先第一點,很多大公司都在用Node.js,並且很多大廠的招聘“高階前端工程師”也明確提出了要掌握Node.js,所以學習Node.js成了我們前端開發者想要獲得高薪,繞不過去的坎。

從現在的招聘資訊來看,全棧是一個大趨勢,兩個前端技術相同的人,如果其中一個人懂後端開發,那麼不管是他的薪酬待遇還是入職概率,都比另一個人要高的多。

當前端工程師瞭解服務端的開發之後,在與後臺開發的溝通,將大大的提高溝通效率,從而提高開發效率。在這不得不說,公司真是個小機靈鬼。

所以,市場逼著我們這些前端開發者要學習服務端開發。

再從投入/回報上看

Node.js是基於JavaScript語言和V8引擎的Web伺服器專案,我們可以直接使用JavaScript來搭架伺服器。

快樂的是,作為前端開發,我們的看家本領就是JavaScript,學習Node簡直不要太輕鬆,這樣是大大的降低了我們學習後端開發的難度。

而且在Node環境下,通過模組化的JavaScript程式碼,加上函數語言程式設計,並且無需考慮瀏覽器相容性問題,直接使用最新的ECMAScript 6標準,可以完全滿足工程上的需求。

在Node.js中,模組化,構建,輔助工具,調優,架構調整,這些東西是無處不在的。在Node環境中的程式設計思想,同時也能提高我們前端開發的質量,這樣相輔相成,讓我們能更快速的提高自己!

所以,學習Node無疑是快速掌握全棧技術的最好途徑

悄悄的告訴你,學Node.js還有一個很大的好處,就是能更清楚的知道,伺服器是怎麼運作的,所以就算是做後臺的,學習Node.js也是妙不可言。

2、Node.js的特點
在說Node.js解決了什麼問題,如何解決痛點之前,有必要先說一下Node.js的特性

Node.js是一個Javascript執行環境

依賴於Chrome V8引擎進行程式碼解釋

事件驅動

非阻塞I/O

輕量、可伸縮,適於實時資料互動應用

單程式,單執行緒

這些特點,不能一條一條的來看,而是要綜合起來一起看

我認為其中有個最重要的一點,那就是事件驅動。這也是為什麼Node.js採用JavaScript單執行緒語言,來做到非阻塞I/O,同時處理萬級的併發而不會造成I/O阻塞的原因。(後面會詳細說明)

其中V8引擎,是Node.js也是採用JavaScript的關鍵因素之一,因為它為JavaScript提供了在非瀏覽器執行環境,V8的高效也是導致Node.js高效的原因之一

3、Node.js解決了什麼問題?
瞭解了Node.js的特性,再來看Node.js解決了什麼問題,就更容易理解了

要學習一門新技術,那我們首先得知道他是要解決了什麼別人解決不了或者是難解決的問題

不然我們一股腦的學了之後,它是用來幹啥的都不知道,又怎麼會知道在什麼時候,應該選擇什麼樣的技術來更優雅的寫BUG呢?

Node.js主要解決了以下兩個頭疼的事情

併發連線

I/O阻塞

什麼是併發連線?有趣的例子

併發這東西,可是吹牛必備啊,想必大家應該都知道併發是個什麼玩意。但畢竟是入門文章,擔心有些人沒什麼印象,這裡還是簡單提一下。

併發(Concurrency): 是指在一個系統中,擁有多個計算,這些計算有同時執行的特性,而且他們之間有著潛在的互動。

看概念很難理解,其實並不複雜,比如“我們吃飯吃到一半,電話來了,我們停了下來接了電話,接完後繼續吃飯,這說明支援併發。”

用程式來解釋就是一群使用者同時來訪問我們的網站/程式。

一般我們在處理併發的時候,都是儘可能的做到讀寫分離,或者分散式部署不同的伺服器,或者直接簡短粗暴的提升我們單機伺服器的效能。

可這樣做要麼是苦逼了程式設計師,要麼就是苦逼了公司的錢包。

我要是公司老闆,能不出伺服器這個錢就肯定不出,畢竟不管是升級伺服器還是擴張伺服器,那都是一筆不小的錢啊。

那就只能苦逼一下員工了咯~可我們又不想這麼苦逼,這時候用Node.js就能幫我們省不少麻煩。

那Node.js又是怎樣處理高併發的呢?

在這裡容我先賣個關子,看完I/O阻塞之後,再來看看Node.js是怎樣處理的。

什麼是I/O阻塞?

先說說I/O是什麼

I/O是input/output(輸入/輸出)

知道I/O之後,接下來的阻塞就很容易理解了。

形象的說,我在餐廳吃飯,就這一個座位,我點完餐後,坐在這享受美食。
然而這時候來了個路人甲,點餐後想坐下吃飯,而這時候我還沒吃完呢,想讓我讓位置給你?不存在的

路人甲只能在旁邊眼巴巴的看著我吃。得等我吃完,走了之後,他才能坐下來吃飯。而這等待的過程呢,就可以叫做阻塞。

這樣做明顯非常不合理嘛

那Node.js是怎麼來解決I/O阻塞的呢?

Node.js遇到I/O事件,並不會先處理,而是先放在事件佇列中,主執行緒依然繼續往下執行,利用非同步操作來處理事件佇列中的事情。

作為一個乾貨文章,怎麼能少的了圖呢?沒圖你怎麼理解?

來看看從使用者請求到伺服器返回資料,Node.js為了應對併發,都做了些啥玩意

我想你現在肯定是懵逼的,那繼續剛才吃飯的例子從頭道來~~~

我跟路人甲同時進入餐館。老闆坐在板凳上等著客人光顧。

我跟路人甲同時找到老闆說“老闆!我要來一份雞腿!”,這時候老闆不樂意了,文明點餐,請取號排隊!

我跟路人甲先後取號坐好後(肯定是我拿的1號,路人甲拿的2號啦,畢竟主角光環在這頂著)

老闆喊來了服務員小A、小B

老闆吩咐“小A啊~去招待1號主角點餐入座點餐”

接著又吩咐“小B啊~去招待2號路人甲入座點餐”

吩咐完後,老闆繼續坐板凳上等著新的客人關顧……

此時小A、小B分別就帶著我跟路人甲去入座點餐

當我或者路人甲吃完飯結賬離開時,老闆都會對我們說“慢走~~~謝謝惠顧,下次再來!”

故事說完,我們們來按照故事解釋一下程式的運作

我跟路人甲就是使用者。
老闆,就是這個程式的主執行緒。
服務員小A,小B就是執行緒池裡的子執行緒。

我跟路人甲同時找到老闆點餐,這就是使用者的併發請求。

老闆管理整個餐廳的運作,發現我們的請求是I/O阻塞呀,所以讓我們排隊取號。這也就是Node.js中維護的事件佇列。

我們點餐之後的入座就餐還有上菜,這些I/O阻塞的事情,都是由服務員來提供服務,老闆並不參與其中。

在我們用餐完畢的時候,會通知老闆我們要結賬離開,結賬離開這個動作就是事件執行完畢後的一個回撥函式。

此時老闆就會跟我們說“慢走~~~謝謝惠顧,下次再來!”,也就是事件執行完後回撥函式的一個操作,並且將執行緒釋放回執行緒池。

現在再回過頭去看圖,是不是清晰的多了。

總結以下:

1、每個Node.js程式只有一個主執行緒在執行程式程式碼。

2、當使用者的網路請求或者其它的非同步操作到來時,Node.js都會把它放到“事件佇列”之中,並不會立即執行它,程式碼就不會被阻塞,主執行緒繼續往下走,直到主執行緒程式碼執行完畢。

3、當主執行緒程式碼執行完畢完成後,通過事件迴圈機制,從“事件佇列”的開頭取出一個事件,從執行緒池中分配一個執行緒去執行這個事件,接下來繼續取出第二個事件,再從執行緒池中分配一個執行緒去執行,一直執行到事件佇列的尾部。期間主執行緒不斷的檢查事件佇列中是否有未執行的事件,直到事件佇列中所有事件都執行完,此後每當有新的事件加入到事件佇列中,都會通知主執行緒按順序取出交程式碼迴圈處理。當有事件執行完畢後,會通知主執行緒,主執行緒執行回撥,執行緒歸還給執行緒池。

以Java、C#為例,在Java、C#中也有辦法實現並行請求(利用子執行緒),但NodeJS通過回撥函式(Callback)和非同步機制,把I/O阻塞處理的更優雅(說人話就是用Code實現起來更簡單易懂,並且效能更好)。

說到這裡,你可能就會問

說好的Node.js是單執行緒的呢?那Node.js怎麼又建立子執行緒了呢?怎麼就跟Java、C#中的執行緒不一樣了呢?怎麼就更優雅了呢?

那就來解釋一波

Node.js使用非同步IO和事件驅動(回撥函式)來解決這個問題。
一般來說,高併發解決方案會提供多執行緒模型,為每個業務邏輯提供一個執行緒,通過系統執行緒切換來來彌補同步I/O呼叫的時間開銷。

像PHP,是一個請求一個執行緒,假如一個執行緒需要2M記憶體,那麼同時有512個請求,就需要1G的記憶體,那同時有5120個請求,就需要10G記憶體,現在記憶體這麼貴的情況下,想想都恐怖。。。

而Node.js使用的是單執行緒模型,對所有I/O都採用非同步的請求方式,在Node.js執行的時候維護著一個事件佇列,程式在執行時進入事件迴圈等待下一個事件到來,每個非同步I/O請求完成後都會被推送到事件佇列中的等待執行。

Node.js是因為是基於JavaScript的特性,所以單執行緒的,但是,單執行緒只侷限於JavaScript部分,Node.js核心還是用C/C++語言編寫的,文章開頭就說到過,它只是給JavaScript提供了一個執行環境而已,它是JavaScript語言的直譯器。

我們所看到的Node.js單執行緒只是一個js主執行緒,本質上的非同步操作還是由執行緒池完成的,Node.js將所有的阻塞操作都交給了內部的執行緒池去實現,本身只負責不斷的往返排程,並沒有進行真正的I/O操作,從而實現非同步非阻塞I/O,這便是Node.js單執行緒和事件驅動的精髓之處了。

所以它跟Java、PHP、C#這些後臺語言的實現的執行緒不一樣的。

關於更優雅呢,主要就是實現起來更容易。比如說在Java、C#中實現多執行緒的時候,總是要注意執行緒安全,這裡要Lock,那裡也要Lock。

一個不注意就得加班熬夜好幾個通宵才能找出問題所在……

而Node.js卻是利用單執行緒執行,Node.js官方也是說不需要鎖。但是不需要鎖,不代表你可以亂來,不需要鎖的是程式碼function,而不是你的資源! 這點要分清楚。

4、搭建我們第一個Node.js伺服器

看了這麼多基礎性的內容,枯燥、乏味,沒勁,看的想睡覺。

現在動手操作一波,刺激一下自己的腎上腺素,一起來搭建一個超簡單的Node.js伺服器

//引用http模組
const http=require(‘http’);

//建立一個服務
//request:伺服器接收的請求資料
//response:伺服器發出的資料
let server=http.createServer((request, response)=>{
  //判斷接收到的url
  switch(request.url){
    case '/hello':
      response.write('hi');
      break;
    case '/word':
      response.write('gun');
      break;
    case '/bb.html':
      response.write ('<html><head></head><body>Talk is cheap,show me the code</body></html>');
      break;
  }
  //關閉
  response.end();
});
//伺服器監聽的埠,填寫埠地址時,注意埠地址不能與其它應用程式衝突
server.listen(8000);

作者:郭小北V5
來源:CSDN
原文:https://blog.csdn.net/xllily_11/article/details/84303153
版權宣告:本文為博主原創文章,轉載請附上博文連結!

相關文章