
1. 我們身邊的Node.js
以前 html+css+js 寫(xiě)前端頁(yè)面的時(shí)候,NodeJs基本上用不到,現(xiàn)在前端都是工程化了,我們一般都是腳手架搭建工程,通常會(huì)在本地開(kāi)啟一個(gè)服務(wù)器,例如vue-cli(npm run serve -> vue-cli-service serve -> webpack-dev-server -> express -> node -> http),本質(zhì)是 node 調(diào)用 http 模塊啟用了一個(gè)web服務(wù)器;再比如我們經(jīng)常用到的 npm(node package manager),這些都與NodeJs息息相關(guān)。
2. Node.js 是什么?
官網(wǎng)解釋:Node.js 是一個(gè)基于 Chrome V8 引擎的 JavaScript 運(yùn)行時(shí)。
個(gè)人理解:它并不是一門(mén)新的語(yǔ)言,本質(zhì)是一個(gè)環(huán)境,能夠讓 JavaScript 獨(dú)立運(yùn)行的這么一個(gè)環(huán)境,將前端開(kāi)發(fā)帶入到了服務(wù)器領(lǐng)域,底層由 C/C++ 開(kāi)發(fā)。
下面是一些關(guān)于 Node.js 的介紹:
先看一張大致的結(jié)構(gòu)圖:

Node.js 發(fā)布于2009年5月,由 Ryan Dahl 開(kāi)發(fā),實(shí)質(zhì)是對(duì) V8 引擎進(jìn)行了封裝, V8 引擎是目前速度最快的 Javascript引擎,chrome瀏覽器就是用的V8解析javascript,在Node中,同樣也采用了V8解析javascript。 libuv 和一些其他庫(kù)拓展了js在前端沒(méi)有實(shí)現(xiàn)的功能,libuv是nodejs的底層支撐,包括事件循環(huán),文件IO,網(wǎng)絡(luò)IO,定時(shí)器等實(shí)現(xiàn)。代碼的結(jié)構(gòu)是(從上往下)nodejs內(nèi)置js模塊,比如http,net,fs,然后內(nèi)置的js模塊是調(diào)用c++層的代碼,比如net模塊調(diào)用tcp_wrap.cc,然后c++層調(diào)用libuv層的代碼,libuv完成任務(wù)后,再往回調(diào)。
特點(diǎn):
- 部署簡(jiǎn)單方便
- 事件驅(qū)動(dòng)
- 單線程(參考鏈接:Node.js真的是單線程嗎?)
- 異步
- 非阻塞 I/O
3. Node.js 能做什么?
設(shè)想這么一個(gè)場(chǎng)景:我們?cè)诓蛷d排隊(duì)點(diǎn)餐,一種排隊(duì)方式是多條隊(duì)伍點(diǎn)餐(多線程,每個(gè)線程需要分配內(nèi)存),每個(gè)客戶需要在那等著廚師做好菜才到下一個(gè)客戶(同步阻塞),這個(gè)方法無(wú)疑會(huì)增加店內(nèi)的人力資源消耗(需要維護(hù)每個(gè)連接,增加了內(nèi)存開(kāi)銷(xiāo));另一種方式是只有一條隊(duì)伍(單線程,減少了內(nèi)存開(kāi)銷(xiāo)),但是我們點(diǎn)完餐后拿到了一個(gè)號(hào)碼,拿到號(hào)碼,我們往往會(huì)在位置上等待,而在我們后面的請(qǐng)求會(huì)繼續(xù)得到處理,收銀員能一直進(jìn)行處理(非阻塞)。
等到飯菜做好了,會(huì)喊號(hào)碼,我們拿到了自己的飯菜,進(jìn)行后續(xù)的處理(吃飯)。這個(gè)喊號(hào)碼的動(dòng)作在NodeJS中叫做回調(diào)(Callback),能在事件(燒菜,I/O)處理完成后繼續(xù)執(zhí)行后面的邏輯(吃飯),這體現(xiàn)了NodeJS的顯著特點(diǎn),異步機(jī)制、事件驅(qū)動(dòng)整個(gè)過(guò)程沒(méi)有阻塞新用戶的連接(點(diǎn)餐),也不需要維護(hù)已經(jīng)點(diǎn)餐的用戶與廚師的連接。
基于這樣的機(jī)制,理論上陸續(xù)有用戶請(qǐng)求連接,NodeJS都可以進(jìn)行響應(yīng),因此NodeJS能支持比Java、PHP程序更高的并發(fā)量,雖然維護(hù)事件隊(duì)列也需要成本,再由于NodeJS是單線程,事件隊(duì)列越長(zhǎng),得到響應(yīng)的時(shí)間就越長(zhǎng),并發(fā)量上去還是會(huì)力不從心。
單線程為什么能夠?qū)崿F(xiàn)高并發(fā)?參考:Nodejs探秘:深入理解單線程實(shí)現(xiàn)高并發(fā)原理
4. Node.js部分內(nèi)置模塊
- os:
os模塊提供了與操作系統(tǒng)相關(guān)的實(shí)用方法和屬性 - process:
process對(duì)象是一個(gè)全局變量,提供了有關(guān)當(dāng)前 Node.js 進(jìn)程的信息并對(duì)其進(jìn)行控制。 作為全局變量,它始終可供 Node.js 應(yīng)用程序使用,無(wú)需使用require()。 它也可以使用require()顯式地訪問(wèn):
const process = require('process');
- fs:
fs模塊可用于與文件系統(tǒng)進(jìn)行交互。
要使用此模塊:
const fs = require('fs');
所有的文件系統(tǒng)操作都具有同步的、回調(diào)的、以及基于 promise 的形式。
- stream:
流(stream)是 Node.js 中處理流式數(shù)據(jù)的抽象接口。stream模塊用于構(gòu)建實(shí)現(xiàn)了流接口的對(duì)象。
Node.js 提供了多種流對(duì)象。 例如,HTTP 服務(wù)器的請(qǐng)求和 process.stdout 都是流的實(shí)例。
流可以是可讀的、可寫(xiě)的、或者可讀可寫(xiě)的。
nodeJS中的流最大的作用是:讀取大文件的過(guò)程中,不會(huì)一次性的讀入到內(nèi)存中。每次只會(huì)讀取數(shù)據(jù)源的一個(gè)數(shù)據(jù)塊。
然后后續(xù)過(guò)程中可以立即處理該數(shù)據(jù)塊(數(shù)據(jù)處理完成后會(huì)進(jìn)入垃圾回收機(jī)制)。而不用等待所有的數(shù)據(jù)。
訪問(wèn)stream模塊:
const stream = require('stream');
盡管理解流的工作方式很重要,但是 stream 模塊主要用于開(kāi)發(fā)者創(chuàng)建新類(lèi)型的流實(shí)例。 對(duì)于以消費(fèi)流對(duì)象為主的開(kāi)發(fā)者,極少需要直接使用 stream 模塊。
- net:
net模塊用于創(chuàng)建基于流的 TCP 或 IPC 的服務(wù)器(net.createServer())與客戶端(net.createConnection())。
使用方法如下:
const net = require('net');
net.createConnection(); // 別名 net.connect(); 客戶端創(chuàng)建連接
net.createServer(); 創(chuàng)建服務(wù)器
- http、http2、https:
若要使用 HTTP 服務(wù)器和客戶端,則可以require('http')。
Node.js 中的 HTTP 接口旨在支持許多傳統(tǒng)上難以使用的協(xié)議的特性。 特別是,大塊的(且可能是塊編碼的)消息。 接口永遠(yuǎn)不會(huì)緩沖整個(gè)請(qǐng)求或響應(yīng),所以用戶可以流式地傳輸數(shù)據(jù)。
5. Express框架
基于 Node.js 平臺(tái),快速、開(kāi)放、極簡(jiǎn)的 Web 開(kāi)發(fā)框架
6. 使用Node.js + Express + Mysql 實(shí)現(xiàn)簡(jiǎn)單的登錄注冊(cè)
詳見(jiàn)附件demo
注意:(使用pm2[https://www.cnblogs.com/panpanwelcome/p/12720384.html], pm2 list, pm2 monit, 啟動(dòng): pm2 start xxx.js[id] --watch[監(jiān)控文件改變并且重啟應(yīng)用],
pm2 stop all/name/id, pm2 delete xxx.js[id])。
pm2 serve <path> <--name xxx> <--watch> <port>(開(kāi)啟一個(gè)文件服務(wù)器)