我是一名剛剛接觸Nodejs有3周左右的新手小白,經歷了迷茫、困頓、挫敗以後終於對Nodejs有了基礎掌握,算是剛剛入門。
我想把我目前所掌握的Nodejs相關知識寫成文章,鞏固本身所學、爲其餘新手小白提供一點點Nodejs入門幫助。javascript
關於個人知識背景,補充幾點:css
言歸正傳,小白教小白入門Nodejs正式開始...html
免責聲明:本文中的知識點、講解內容僅僅是我我的目前的理解,不敢保證100%都是正確的,僅供參考,同時歡迎批評指正。前端
Nodejs官方對本身的介紹很是簡單——Node.js 是一個基於 Chrome V8 引擎的 JavaScript 運行環境。java
Nodejs與網頁JS的區別:node
JS和Nodejs雖然都遵循ECMAScript標準(都是Javascript),可是運行環境不一樣,擁有的API不一樣,因此他們功能相差很大。python
相同點:
對於一些基礎類型語法,好比String、Array、Date,ES6新語法等,JS和Nodejs是沒有區別的。git
不一樣點:
好比JS能夠操做網頁元素(好比修改CSS樣式),擁有瀏覽器中的windows對象、擁有鼠標事件等,Nodejs都不具備這些——因此JS是前端。
一樣Nodejs能夠操做系統底層文件,建立服務監聽,而JS都不具備這些——因此Nodejs是後端。github
Nodejs的優點:
相對其餘編程語言,好比Java/.Net/python,這些語言可以作的事情很是很是多,好比開發桌面軟件或APP,Web服務端只是他們衆多應用領域中的其中一種,而Nodejs從誕生到如今惟一用途就是Web服務端。正則表達式
那些語言對於計算能力要求比較高,屬於CPU(或GPU)操做頻繁,也稱「CPU密集」,(好比用Python寫大數據處理、人工智能、區塊鏈等,對於計算量要求比較大),而Web服務對數據計算量少,但對I/O(文件讀寫)操做頻繁,也稱「I/O密集」,恰好正式Nodejs的優點。
Nodejs是I/O異步非阻塞:
能夠答應幹不少活,至於何時幹完不能保證,可是答應過的就必定會去幹,只是早晚而已。
拿比喻來講,異步非阻塞至關於一個飯店裏的店小二,來一位客人就記錄他點的菜,並把所點的菜名傳遞給後廚,接着就能夠接待下一位客戶,至於後廚何時作好店小二不能保證,可是若是後廚把飯菜作好後,店小二可以精準的把飯菜送到對應客人的桌子上。
與之對應的是「I/O阻塞」,好比Apache服務器:
答應一件事,必須作完了才能夠去作另一件事,若是須要處理不少事就會一件件堆積「阻塞」起來。
還拿飯店店小二來比喻,就是來一個客人,這個店小二記錄他點的菜,而後把所點的菜名傳遞給後廚,而後很是耐心等待後廚作菜(這個時候又來了一位顧客,這個店小二也不去理會新客人,依然守在後廚門口耐心等待第一位客人的菜是否作好),時間過去了10分鐘,店小二和第二位顧客沒有任何溝通,第二位客人一臉懵,跟着店小二一塊兒等待。當後廚把第一位客人的飯菜作好,店小二把飯菜送到第一位客戶桌子上,說了一句:對您的服務已完成,我終於能夠去接待第二位顧客了。這時候纔去找第二位顧客,詢問你吃點什麼?
想象一下上面「非阻塞」和「阻塞」對應的飯店場景,在現實生活中哪一個更合理?哪一個飯店能更好生存下去?
若是不能理解異步非阻塞,學Nodejs會很艱難。會被各類狀況下的箭頭函數弄懵,因此上面就多囉嗦了幾句。
聽說,Nodejs性能是Php的80倍。 Php纔是最好的語言。
軟件下載地址:http://nodejs.cn/download/
根據本身電腦系統選擇對應版本下載,並一路下一步安裝。
VSCode簡介:全稱Visual Studio Code,是微軟推出的一款免費軟件開發IDE。
優秀的IDE有不少,好比HBuilderX、Sublime等,爲何Nodejs開發首選IDE是VSCode?
選擇VSCode的3個理由:
一、TypeScript是微軟開發的(雖然Nodejs入門時還用不到,但未來必定會用到),VSCode也是微軟開發的,毫無疑問VSCode是支持TypeScript最好IDE。
二、VSCode內置DOS操做窗口,調試Nodejs很是方便。
三、VSCode插件擴展衆多,自己仍是免費軟件。
VSCode安裝:
軟件下載地址:https://code.visualstudio.com...
根據本身電腦系統選擇對應版本下載,並一路下一步安裝。
NPM是隨同NodeJS一塊兒安裝的包管理工具,除了Nodejs默認自帶的包(類模塊),平常開發會須要大量別人封裝好的包(類模塊),這些每次都須要從國外服務器上下載,爲了快速下載和安裝,可使用淘寶國內的npm鏡像:cnpm。
關於cnpm的具體介紹、安裝方法,使用方法,參見其官網:https://npm.taobao.org/
小結:
至此,已經完成了Nodejs開發環境的安裝,對Nodejs有了一點點初步印象。在正式開始學習Nodejs以前,須要一些計算機網絡通訊基礎知識,如今進入下一章。
如下每個知識點均可以無限展開來說,可是做爲Nodejs入門的知識儲備,這裏只講最基礎的那個點,夠入門用便可。
協議規定:任何一條網絡傳輸消息(也稱報文)都必須由:消息頭(字符串形式) + 消息內容主體(二進制數據) 兩部分構成。
補充說明:
先後端傳遞數據時,須要寫清楚是以"GET"仍是"POST"方式發送,這裏面的區別是什麼?其實就是告訴對方:
若是是"GET"方式,代表我(發送方)把數據寫在了「消息頭」裏,你(接收方)記得從「消息頭」裏獲取。 數據傳遞表現形式爲:http://www.xx.com/xx?name=puxiao&qq=78657141,這類數據比較簡單,信息量比較小。 若是是"POST"方式,代表我(發送方)把數據寫在了「消息主體」裏,你(接收方)記得從「消息主體」裏獲取。 數據不會在網址中出現,傳遞數據內容較大,好比上傳一張圖片或獲取一個網頁。
雖然本篇入門爲「靜態資源服務器」,不牽扯「動態數據交互」,可是瞭解上面知識點很是重要。
瀏覽器與服務器約定好的緩存依據,一共有4種方式:強制緩存(2種) + 協商緩存(2種)
強制緩存的2種方式:
一、Expires (到期時間,字符串形式(GMT或UTC形式))
服務端返回信息頭對應爲:res.setHeader['Expires',(new Date(Date.now() + 3600)).toGMTString()];//將當前服務器時間+3600毫秒,產生新的日期時間,並將該時間轉換爲GMT字符串形式
缺點:若客戶電腦時間不正確,或不一樣時區,不能保證必定和服務器時間匹配,可結合Cache-Control使用。
二、Cache-Control (有效期爲多少秒)
服務端頭返回信息頭對應爲:res.setHeader['Cache-Control','max-age=60'];//告訴瀏覽器60秒內不用詢問我,可直接使用本地緩存
補充說明:
將秒數設置比較小,可進行數據緩存策略,好比某一塊數據10秒內就使用本地緩存。
將描述設置比較大(好比N天),可進行靜態文件緩存策略,好比某圖片或css文件N天以內均可使用本地緩存。
協商緩存的2種方式:
一、Modified (修改時間,字符串形式(GMT或UTC形式)):服務端Last-Modified/客戶端If-Modified-Since
服務端獲取某文件的修改時間代碼爲:stats.mtime.toGMTString(); 將服務器獲取文件的修改時間與客戶端文件修改時間進行對比,若相同則返回304,若不相同則發送新的文件給客戶端
特別提醒:在req.headers中,默認將瀏覽器消息頭中的大寫改成了小寫,因此正確獲取應該是res.headers['if-modified-since']。
二、Etag (電子戳):服務端Etage/客戶端If-None-Match
1.能夠簡單採用 文件大小 + 文件修時間,將獲得字符串值約定爲電子戳(可針對此值進行md5換算以便更加精準) 2.將服務器獲得文件電子戳與客戶端文件電子戳進行對比,若相同則返回304,若不相同則發送新的文件給客戶端
補充說明:
更多狀態碼可查看:https://developer.mozilla.org...
正則表達式、箭頭函數、ES6新語法都屬於JS的基礎知識,若是你不熟悉,建議先百度瞭解。
在學習Nodejs以前,確定見過聽過各類全棧名詞,雖然Nodejs入門還都用不到這些框架和技術,可是先了解一下他們是作什麼的,作到心中有數,當看到別人說這些名詞時,不慌不亂。
如下關於計算機的進程、線程名詞解釋、CPU任務分配原則,若不感興趣或理解不了(由於我也僅僅是有一個很大概、粗略的認識,若是說錯了敬請見諒 ),能夠跳過。
進程:假如電腦上目前運行的程序有Photoshop、QQ、Nodejs,每個程序都對應一個進程,一個CPU會給每個進程分配必定的內存。
線程:一個進程中能夠有多個線程,全部這些線程共享這個進程中的資源(內存、計算能力),若是其中一個線程發生錯誤則會影像整個進程。
單線程:一個進程中只有一個線程(如Nodejs)
缺點:一瞬間只能作一件事
優勢:進程中就本身一個線程,精力更加集中(徹底擁有本身所屬的進程擁有的所有內存資源調度)
單進程多線程:一個進程中可建立多個線程(如Apache)
優勢:能夠經過創造多個線程,一瞬間能夠同時作多件事情
缺點:CPU分配給本進程的資源是固定的,因此可以建立線程的數量是有限的,而且由於每一個線程共享一個進程,因此如有一個線程出問題卡住了,會影響其餘線程,進而影響整個進程。
「Nodejs自己爲單進程單線程」,聽上去沒有多線程強大,可是Nodejs說本身是單線程,真的是這樣嗎?
還記得開頭是怎麼介紹Nodejs的嗎?「Node.js 是一個基於 Chrome V8 引擎的 JavaScript 運行環境。」
沒錯,Nodejs背後靠山是Chrome V8,而這個V8在調用系統底層進行I/O操做時是多線程的,進而能夠約等於說Nodejs是"多線程"的。(背靠V8好乘涼)。
等一等!以上關於進程、線程、內存資源分配都是在電腦單核CPU的前提下,那若是電腦是多核CPU,那是又是什麼狀況呢?
多核CPU處理進程,任務分配原則:
假如電腦(服務器也是電腦)是4核處理器:A核、B核、C核、D核,那麼平時電腦是怎麼處理分配資源給不一樣進程呢?
好比電腦上恰好運行了4個程序(進程):PS、QQ、迅雷、Nodejs。
電腦怎麼安排任務?會不會是讓A核來處理PS,B核來處理QQ,C核來處理迅雷,D核來處理Nodejs?
答案是不會!
現實的狀況很殘酷(能者多勞原則),爲了整體性能,電腦的任務安排是:
A核你來處理PS、你來處理QQ,你來處理迅雷,你來處理Nodejs。
B核、C核、D核大家都歇着,何時A覈實在忙不過來了,B核你再上!
固然上面論述只是作了適當誇張,實際中還會加入別的平衡策略。
默認Nodejs是單進程,即便電腦上是多核CPU,也只能使用其中一個CPU而已。
可是能夠經過Nodejs自帶的類模塊:cluster(集羣)來實現多進程(實際上是子進程,每一個子進程裏依然是一個單線程),幾核CPU能夠分裂出幾個子進程,充分利用好多核CPU的性能。
在Nodejs開發過程當中,咱們須要不斷引用別人編寫好的代碼包。
關於NPM更多中文介紹,能夠訪問:https://www.npmjs.cn
再次強調一下,npm代碼包都存放在國外服務器上,咱們爲了方便最好使用淘寶的npm國內鏡像服務,即cnpm。
NPM引入(安裝)第三方代碼包的幾個知識點:
其中--save和--save-dev的區別略微有一點繞,若是不明白能夠百度或者暫時先放一下,不影響本文後續編程。
本篇入門文章講的「建立靜態資源服務器」所用到的代碼模塊,都是Nodejs內置的(由於這些模塊太基礎、使用太頻繁,因此Nodejs內置了這些模塊),只須要引入2個別人的代碼包。
第1個:@types/node
默認在VSCode裏建立的項目只有網頁JS代碼提示,缺乏Nodejs的代碼提示(沒有代碼提示不表明不能正常運行),因此在本次代碼示例中,咱們須要引入一個叫「@types/node」的代碼包。
關於@types/node,可訪問官方地址(英文):https://www.npmjs.com/package...
官方提供的安裝示例:
npm install --save @types/node
1. install 可簡寫爲 i,即 npm i --save @types/node 2. npm 可替換爲 cnpm,即:cnpm i --save @types/node
有些時候,若是使用cnpm安裝不成功(極少狀況),只能用npm,爲了下載代碼包快一些,咱們能夠經過新增一個參數,繼續使用淘寶國內鏡像文件。
上述安裝代碼可修改成:
npm i --save @types/node --registry=https://registry.npm.taobao.org
第2個:art-template(模板引擎)
當返回某個目錄內的資源列表式,經過這個模板引擎生成對應頁面。
Nodejs模板引擎有很是多種,常見的有:handlebars、jade、ejs、art-template
本次咱們選擇使用art-template,詳細使用方法請訪問:https://aui.github.io/art-tem...
擁有面對對象編程經驗的人都知道,一個複雜的項目必定須要被拆分紅多個小模塊,每一個小模塊又會繼續往下劃分不一樣的類,每個類擁有本身的屬性、方法。
目前不管網頁JS仍是Nodejs,都不是傳統的面對對象語言(儘管ES6之後已經很是進步了、Typescript就是爲了彌補這個缺憾而誕生的,Typescript模擬出了相似面對對象的編程寫法,但僅僅是模擬並非原生),沒法提供標準意義上的「類」。
因而有了Commonjs模塊化這個概念(本文一直稱呼這種代碼形式爲類模塊或代碼模塊),詳細介紹能夠參考:http://javascript.ruanyifeng....
類模塊實現方法是經過內置的module類的exports屬性,來對外聲明(提供)本身內部屬性和方法的調用。
這裏的某個類模塊其實就是一個編寫好的.js文件。
調用方則經過 const xx = require('./xxx.js') 來將xxx.js模塊引入到本身內部(其餘面對對象語言通常都採用import xxx的形式引入)。
如下爲我的對Commonjs模塊化的一個理解:
仍是以其餘面對對象語言(好比jave、AS3)來和Commonjs模塊化作對比。
其餘面對對象語言的屬性和類,在聲明以前都會有訪問修飾符,好比public(公開)、private(私有)、protect(僅子類可見),static(歸屬於類的,而非實例的)。
Commonjs模塊化的exports表現出來的,特別像其餘語言中的「public static」這個概念。
被引入的類模塊(代碼模塊),「不須要實例化(也沒辦法實例化)」,使用起來相似「面對對象中類的公開靜態屬性或方法」。
以上僅爲我我的理解,當我把module.exports理解爲 public static 後,我對於Commonjs模塊化一會兒清晰了不少。
想學任何一門編程語言,最應該先看、多看、反覆看的就是他們的官方幫助文檔,Nodejs中文文檔請訪問:http://nodejs.cn/api/
內置代碼模塊太多,做爲剛開始入門,沒有必要和精力所有看完。
本文講的建立靜態資源服務器,只須要看如下幾個點便可:
http(建立http server服務) :http://nodejs.cn/api/http.html
僅看http類模塊整體介紹和http.createServer方法便可
path(資源路徑相關) :http://nodejs.cn/api/path.html
全看
fs(文件系統) :http://nodejs.cn/api/fs.html
fs整體介紹、fs.stat方法、fs.Stats類、fs.readdir方法(讀取某個文件夾的內容)、fs.createReadStream(以流的方式讀取某個文件)
這裏讀取文件咱們不使用fs.readFile方法,由於該方法只有把文件所有讀取完成後纔會觸發後續事件,不像createReadStream方法,以流的形式讀取(讀取一點就輸出一點)。
module(內置模塊,即Commonjs模塊化) :http://nodejs.cn/api/modules....
僅看module.exports便可
process(內置進程類模塊) :http://nodejs.cn/api/process....
僅看process.cwd()便可。
zlib(壓縮) :http://nodejs.cn/api/zlib.html
僅看zlib整體介紹、zlib.gzip方法和zlib.createGzip方法、
通常網頁有3中壓縮方式:gzip、deflate、br,這3種壓縮方式在zlib中的使用方法相似,只是類的名字不同而已。
這3個用法相似:zlib.gzip、zlib.deflate、zlib.brotliCompress(注意不是zlib.br)
這3個用法相似:zlib.createGzip、zlib.createDeflate、zlib.createBrotliCompress(注意不是zlib.createBr)
Nodejs目前一共有41個內置類模塊,而上面已列出的有6個模塊,耐心看完,後續代碼照着再反覆敲幾遍,真的能夠達到Nodejs入門的標準了。
---前面鋪墊了那麼多,終於該進入項目正式內容了---
本次開發的項目名稱爲「建立本地靜態資源服務器」,咱們分析一下這個Nodejs項目須要知足的業務內容。
從用戶的角度講,他的操做流程是:
1. 在瀏覽器地址欄中輸入本地請求地址,如http://127.0.0.1:8899 摁回車 2. 網頁顯示出根目錄下的靜態資源內容:各類文件(如.html、.jpg、.js等)和文件夾 3. 若點擊某個文件,則經過網頁打開此文件 4. 若點擊某個文件夾,則顯示該文件夾內的資源:各類文件(如.html、.jpg、.js等)和文件夾
須要考慮的意外狀況有:
從後臺的角度講,他的業務流程是:
1. 建立一個本地http服務,靜靜開始等待用戶訪問併爲其提供服務 2. 偵聽到用戶的http請求,分析url地址獲取到請求資源地址,並將該地址轉化爲本地資源地址 3. 嘗試獲取該資源信息 4. 若發現本地不存在該資源,向用戶發送404,告知用戶該資源不存在 5. 若發現本地該資源存在,則判斷該資源是文件仍是文件夾 6. 如果文件,則將該文件內容發送給用戶 7. 如果文件夾,則將該文件夾內資源信息,整理髮送給用戶
須要額外考慮的幾點:
根據上述的需求分析,能夠大致梳理出後端業務執行流程,以下圖:
注意,當你訪問任意某個資源時,瀏覽器會額外多一條針對站標favicon.ico文件的請求,咱們忽略這個便可。
以windows系統爲例,假設咱們要將本項目全部源代碼存放在F:\node\hello中。
項目初始化的操做步驟是:
此致項目Nodejs初始化第一階段完成,下一步開始第二階段:引入咱們須要使用的2個第三方類模塊
項目初始化後,緊接着要進行VSCode調試配置,操做步驟及流程,以下圖所示:
調試配置設置:
至此,終於能夠開始編寫代碼了。
這裏直接列出項目結構:
項目結構說明:
./config/config.js 用來存放一些基礎配置常量,好比要建立服務的端口889九、哪些格式的文件須要被壓縮等
./config/mimetype.js 用來存放服務器支持的文件格式以及該文件格式對應消息頭部中的Content-Type
./view/404.html 定義好的404頁面
./view/dir.html 定義好的目錄頁面模板
./cache.js 用來處理緩存相關的類模塊
./compress.js 用來處理壓縮相關的類模塊
./index.js 項目啓動js,用來建立http服務,並根據用戶url請求得到對應資源在服務器的絕對路徑
./route.js 整個項目核心類模塊,根據請求資源路徑進行一系列後續操做
不少服務端框架都有「路由」這個概念,這裏的route.js的做用就是將資源請求進行下一步分配(判斷)並進行迴應。
這裏就不針對每一個js類模塊展開來說了,你能夠直接下載個人項目源碼進行分析。
項目源文件下載地址:https://pan.baidu.com/s/1Chbg... 密碼:g4yy
在VSCode中進行調試,正常運行結果以下:
爲啥不展開來說?每一個類模塊具體都是什麼代碼,具體實現了哪些功能不該該是本篇文章的核心嗎?
我是這樣認爲的:
我但願你必定先把官方幫助文檔看明白、而後再看我提供的源碼、而後再本身從頭寫一遍。
這樣你才能真正入門,才能真正領悟到Nodejs的開發編寫思路。
若你真的真的基礎太差,理解不了,可私信給我。
Nodejs思想,網絡通訊知識才是最難理解和須要學習的那部分,再次強調一下,那些具體的代碼僅僅是一個表象而已。
但願你養成一個好的學習、解決問題的方法:看官方文檔、在思否/掘金上搜索或提問、或百度一下。
小白教小白Nodejs入門是我花了2天時間寫出來的第一篇Nodejs技術分享文章,感謝你的閱讀。
明天就是2020年1月1日,咱們一塊兒加油!