400-650-7353
Node是什么
官方解釋:Node.js 是一個基于 Chrome V8 引擎的 JavaScript 運行時。 也就是說Node.js不是一種獨立的語言,與PHP、JSP、Python的“既是語言,也是平臺”不同,Node.js的語法是Ecmascript,運行在谷歌V8引擎上。
與PHP、JSP等相比(PHP、JSP、.net都需要運行在服務(wù)器程序上,Apache、Nginx、IIS。),Node.js跳過了Apache、Nginx、IIS等HTTP服務(wù)器,它自己不用建設(shè)在任何服務(wù)器軟件之上,可以很方便地任意擴展web服務(wù)器。Node.js的許多設(shè)計理念與經(jīng)典架構(gòu)(LAMP = Linux + Apache + MySQL + PHP)有著很大的不同,可以提供強大的伸縮能力。
Node的特點
Node平臺的特點也決定了它可以開發(fā)出什么產(chǎn)品。
1.單線程
在Java、PHP或者.net等服務(wù)器端語言中,會為每一個客戶端連接創(chuàng)建一個新的線程。而每個線程需要耗費大約2MB內(nèi)存。也就是說,理論上,一個8GB內(nèi)存的服務(wù)器可以同時連接的最大用戶數(shù)為4000個左右。要讓W(xué)eb應(yīng)用程序支持更多的用戶,就需要增加服務(wù)器的數(shù)量,而Web應(yīng)用程序的硬件成本當然就上升了。
Node.js不為每個客戶連接創(chuàng)建一個新的線程,而僅僅使用一個線程。當有用戶連接了,就觸發(fā)一個內(nèi)部事件,通過非阻塞I/O、事件驅(qū)動機制,讓Node.js程序宏觀上也是并行的。使用Node.js,一個8GB內(nèi)存的服務(wù)器,可以同時處理超過4萬用戶的連接。
另外,單線程的好處還有操作系統(tǒng)完全不再有線程創(chuàng)建、銷毀的時間開銷。
壞處,就是一個用戶造成了線程的崩潰,整個服務(wù)都崩潰了,其他人也崩潰了。
如以下圖:單線程就像是公路上的單行線,來來往往的車輛不停的走,不浪費資源,并且一輛一輛的通告。但是如果一旦有一輛車出現(xiàn)事故,就會影響整個線程。而多線程就像是多車道,有一條線出了問題還可以從其它路線中通行。
單線程:
多線程:
單線程問題:
多線程問題:
2.非阻塞I/O
I/O操作指的是對磁盤的讀寫操作。傳統(tǒng)的服務(wù)器語言大多是多線程、阻塞式 I/O。這也是 Node 與眾不同的地方,對于傳統(tǒng)的服務(wù)器語言,在與用戶建立連接時,每一個連接都是一個線程。 當有十萬個用戶連接時,服務(wù)器上就會有十萬個線程。而阻塞式 I/O 是指,當一個線程在執(zhí)行 I/O 操作時,這個線程會阻塞,等待 I/O 操作完成后繼續(xù)執(zhí)行。
例如,當在訪問數(shù)據(jù)庫取得數(shù)據(jù)的時候,需要一段時間。在傳統(tǒng)的單線程處理機制中,在執(zhí)行了訪問數(shù)據(jù)庫代碼之后,整個線程都將暫停下來,等待數(shù)據(jù)庫返回結(jié)果,才能執(zhí)行后面的代碼。也就是說,I/O阻塞了代碼的執(zhí)行,極大地降低了程序的執(zhí)行效率。
阻塞模式下,一個線程只能處理一項任務(wù),要想提高吞吐量必須通過多線程。而非阻塞模式下,一個線程永遠在執(zhí)行計算操作,這個線程的CPU核心利用率永遠是100%。所以,這是一種特別有哲理的解決方案:與其人多,但是好多人閑著;還不如一個人玩命,往死里干活兒。
3.事件驅(qū)動
在Node.js中,客戶端請求建立連接,提交數(shù)據(jù)等行為,會觸發(fā)相應(yīng)的事件。在Node.js中,在一個時刻,只能執(zhí)行一個事件回調(diào)函數(shù),但是在執(zhí)行一個事件回調(diào)函數(shù)時,可以轉(zhuǎn)而處理其他事件(比如,又有新用戶連接了),然后返回繼續(xù)執(zhí)行原事件的回調(diào)函數(shù),這種處理機制,稱為“事件環(huán)”機制。
Node.js底層是C++(V8也是C++寫的)。底層代碼中,近半數(shù)都用于事件隊列、回調(diào)函數(shù)隊列的構(gòu)建。用事件驅(qū)動來完成服務(wù)器的任務(wù)調(diào)度。用一個線程,擔(dān)負起了處理非常多的任務(wù)的使命。
單線程,單線程的好處,減少了內(nèi)存開銷,如果某一個事情,進入了,但是被I/O阻塞了,所以這個線程就阻塞了。非阻塞I/O, 不會等I/O語句結(jié)束,而會執(zhí)行后面的語句。
非阻塞就能解決問題了么?比如執(zhí)行著A的業(yè)務(wù),執(zhí)行過程中,B的I/O回調(diào)完成了,此時怎么辦?
事件機制,事件環(huán),不管是新用戶的請求,還是老用戶的I/O完成,都將以事件方式加入事件環(huán),等待調(diào)度。
Node可以做什么
正是因為Node的3個特點,node非常適合做任務(wù)調(diào)度而不擅長做大量的邏輯運算,因為大量的運算又會造成嚴重的阻塞。
比如:
● Web服務(wù)API,比如REST
● 后端的Web服務(wù),例如跨域、服務(wù)器端的請求
● 基于Web的應(yīng)用
● 多客戶端的通信,如即時通信
Node的模塊化思想
模塊化是指解決一個復(fù)雜問題時自頂向下逐層把系統(tǒng)劃分成若干模塊的過程,有多種屬性,分別反映其內(nèi)部特性。是一種處理復(fù)雜系統(tǒng)分解為更好的可管理模塊的方式。
在前端中且主要是JavaScript的使用情況下。存在兩大問題,文件依賴和命名沖突。
所以在使用JavaScript的時候,要迫切擺脫這樣的問題。在Node中提供了非常好用的Commonjs規(guī)范,具體實現(xiàn)在module.exports/exports、require上。我們在開發(fā)中,讓一個js就是一個模塊,多個模塊可以組成完整應(yīng)用,抽離一個模塊不會影響其他功能的運行。在主文件中只需運行一個文件即可,其它文件依賴誰讓它們自己管理。
總的來說:模塊化是開發(fā)者管理代碼的一種規(guī)范而已。
- // index.js
- var m = require( "./module.js" );
- m.foo()// 打印hello ujiuye
-
-
- // module.js
- function foo(){
- console.log('hello ujiuye')
- }
- // 導(dǎo)出foo
- exports.foo = foo;
Node安裝
Node.js的官網(wǎng)為:https://nodejs.org/en/
安裝包的下載地址:https://nodejs.org/en/download/
在LTS(Long Term Support,長期支持版)的選項卡下,根據(jù)不同平臺系統(tǒng)選擇你需要的 Node.js 安裝包并下載:如下圖:
步驟一: 雙擊下載后的安裝包 node-v12.14.0-x64.msi,并點擊運行,如下圖。
步驟二:點擊以上的運行,將出現(xiàn)如下界面,點擊Next繼續(xù):
步驟三:勾選接受協(xié)議選項,點擊 Next(下一步) 按鈕 :
步驟四:Node.js默認安裝目錄為 "C:\Program Files\nodejs" , 你可以修改目錄,并點擊 next(下一步):
步驟五: 默認Node.js的安裝模式 , 直接點Next(下一步)
這里共有4項安裝內(nèi)容:
1.安裝Node核心模塊
2.安裝npm
3.安裝文檔
4.把Node.js和npm及其模塊添加到環(huán)境變量
這里可以看到1和2就是Node核心程序和npm,安裝Node的時候,默認會把Node和npm都安裝上了。 另外4是把Node和npm添加到環(huán)境變量,如果不選,之后在cmd窗口想運行node、npm等執(zhí)行程序會報錯,系統(tǒng)找不到指定文件,當然也可以再手動配置系統(tǒng)環(huán)境變量。
這里建議全選,也就是默認選項,直接 Next
步驟六:點擊next,然后繼續(xù)安裝。
步驟七:點擊Install開始安裝。
安裝過程:
步驟八:結(jié)束安裝Node.js:
在cmd中,輸入命令node -v,檢查Node.js的版本號。
使用Node定義Http服務(wù)
安裝node.js環(huán)境 ,然后建立app.js文件,編寫如下代碼,在終端輸入 node app.js命令。可以看到終端中輸出 3000端口開啟。
那么就可以輕松搭建一個非常簡單的服務(wù)器啦。然后在瀏覽器訪問 http://localhost:3000 就可以訪問到 hello ujiuye。
- //1. 引入核心模塊http
- const http = require('http');
-
- //2. 創(chuàng)建服務(wù)器 http.createServer
- let server = http.createServer( (request,response)=>{//request|req 請求對象 , response|res響應(yīng)對象
- response.end('hello ujiuye')
- } )
-
-
- //console.log( server.listen )
- server.listen( 3000 ,()=>{ //端口開啟成功,則執(zhí)行此回調(diào)
- console.log('3000端口開啟');
- });