Node.js(day3)
一、模組系統
1.什麼是模組
Node.js中常用的核心模組有:
- http模組
- fs檔案系統模組
- url模組
- path模組
- os系統模組
在使用Node.js中我們發現每個js之間是沒有聯絡的,都是單獨的一個作用域,這就是模組系統的設計。(相關概念請參考CommonJs規範)
簡言之,Node.js中的js不像普通的js具有全域性變數,而是以模組(檔案)為作用域,不會汙染其他檔案。而使用者書寫的js就是自定義模組,下載安裝的就是第三方模組,自帶的js就是核心模組。
既然模組沒有了全域性作用域,那麼我們需要使用模組就需要進行載入和匯出通訊規則。 - 載入:
require()
匯出:
exports | module.exports
2.exports和module.exports的區別
首先兩者都是js檔案(模組)用於匯出變數的物件,如果你執行這樣的語句:
console.log(exports === module.exports);
你會發現結果為true。也就是說這兩個變數其實是指向同一個物件的引用。
底層原始碼類似這樣:
var module = {
exports:{}
}
var exports = module.exports;
所以我們可以使用exports或module.exports來匯出變數。其實exports的作用就是簡化module.exports的書寫而已。
但是需要注意的是,不能對exports直接賦值,類似exports = function(...);這樣就切斷了var exports = module.exports;
return module.exports
,所以使用exports時注意不能進行賦值操作即可。
3.require載入規則
直接說結論:
require載入本質上都是在載入檔案來實現模組功能
- 載入自定義模組
我們在載入自定義檔案時只需要寫明檔案路徑即可(基本都會使用相對路徑)。
比如在我們需要在a.js中價值b.js。(假設在同一級目錄),我們只需要寫:
var bExports = require('./b');//字尾可省略
另外,require有一個載入機制就是:優先從快取載入
。
比如現在同級目錄下還有一個c.js,且b.js和a.js中都有require('./c')這樣的語句。
結果就是:執行a.js --> 載入b.js -->載入c.js -->結束。
注意,這裡c.js並不會載入兩次
- 載入核心模組
對於核心模組的載入,我們可能沒有見到什麼js檔案,這其實是Node.js為了使用者方便使用直接為我們提供了模組對於的名稱,比如http就代表http模組,require('http')其實也是載入了檔案的,只是不是直接載入js檔案,而是編譯後的二進位制檔案。 - 載入第三方模組
首先要使用第三方模組必須使用npm下載安裝。
比如載入art-template模組,我們只需要:
var template = require('art-template');
第三方模組最終也是加在執行js檔案,尋找需要載入檔案的步驟為(以require(art-template)):
- 在執行的js檔案的同級檔案目錄下尋找
node_modules
資料夾(npm安裝的時候會自動建立) - 在node_modules下找到art-template目錄
- 找到package.json檔案,讀取鍵為
main
的值,一般為index.js
。 - 載入找到的js檔案。
- 以上情況為正常情況,也可能出現node_modules、art-template、package.json檔案、main值找不到的情況,如果是art-template能找到,後面的檔案找不到會預設執行index.js,如果index.js也不存在這是會
向上一級查詢node_modules目錄
,然後重複以上查詢規則,直到找到或查詢值磁碟根目錄,如果最終都沒有找到可以執行的檔案會報cannot find module 'art-template'
的錯誤資訊。
二、包說明檔案
上面說到require()在載入第三方模組時會使用到package.json
檔案,這個檔案就是包說明檔案。包說明檔案中包含了關於包(模組)的相關資訊,比如入口main、依賴dependencies等。
當我們使用npm install art-template安裝art-template模組時,發現生成的node_module檔案目錄下除了art-template還有許多其他模組,這是因為art-template模組本身也依賴了其他的一些模組,所以也需要安裝,以此類推依賴包的依賴包也需要安裝。
但是這樣會存在一個問題,當我們的專案很大,使用的模組也變多的時候,我們可能會忘記我們使用了哪些依賴包,所以我們希望在某個檔案下將依賴包的資訊記錄下來,這是package.json包說明檔案的另一個作用。
在安裝目錄下新建一個package.json檔案,內容為{}(必需),我們安裝模組時常用下面語句(--save
)
npm install art-template --save
然後開啟package.json檔案,發現多了依賴資訊:
這樣,我們就能記錄專案的依賴包資訊。(高版本的npm無論有沒有--save都會產生一個package-lock.json檔案,裡面記錄的是本次下載安裝所有依賴包資訊)
我們不必每次都手動建立package.json檔案,而是使用npm init
來建立。
然後會出現一步一步讓我們填寫關於本專案的基本資訊,可一路回車,使用預設設定。另:npm init --y
可跳過設定,直接初始化完成。然後我們發現目錄下建立了一個package.json檔案,並寫入了相關資訊:
三、npm常用命令
- 版本檢視
npm --version
npm -v
- 更新npm
npm insatll npm --global
- 安裝包
npm install
npm install 包名
npm intsall 包名 --save
- 解除安裝包
npm uninstall
npm uninstall 包名
npm uninstall 包名 --save
- 使用幫助
npm help
npm 命令 --help
- 簡寫形式
--version 簡寫為 -v
install 簡寫為 i
uninstall 簡寫為 un
--save 簡寫為 -S
--help 簡寫為 -h
--global 簡寫為 -g
四、解決npm被牆的問題
某些npm包資源需屬於境外資源,可能被牆,這種時候可能出現安裝較慢或失敗的情況,為了解決這個問題可以安裝npm的國內映象:cnpm
cnpm是淘寶團隊對npm在國內的備份,官網地址:點這裡
安裝很簡單:
//必需安裝到全域性
npm insatll cnpm -g
然後使用cnpm進行包安裝即可,例如:
cnpm install art-template
五、初體驗:第三方模組Express
Express是高度整合的http模組,提高了我們直接使用http模組進行開發web伺服器的效率。
相關介紹及使用可參考官網Express。
1.安裝
npm install express --save
2.helloWorld
var express = require('express');
//建立web服務
var app = express();
//建立伺服器視窗
app.listen(8000,function(){
console.log('server running...');
});
//get請求事件
//當以get方式請求為'/'時觸發
app.get('/',function(req,res){
res.send('hello express.你好express!');
});
//當以get方式請求為'/about'時觸發
app.get('/about',(req,res) => {
res.send(`
<!DOCTYPE html>
<html>
<head>
<title>About me</title>
<meta charset="utf-8">
</head>
<body>
<h1>我是Express...</h1>
</body>
</html>
`
);
});
訪問情況:
我們發現express相比http簡化了一些,首先是api比較簡單,其次是對請求的url進行了處理,我們不用再使用request.url來注意判斷,,然後是訪問不到的路徑也進行了處理,最後就是Conten-Type也不需要我們手動設定了。當然express的優點不止這些,後續會逐漸用到。
3.express處理靜態資原始檔
在之前的http核心模組中我們如果要訪問某個目錄下的資原始檔,需要進行統一處理,然後再根據request.url來判斷並使用fs檔案系統模組來讀取檔案並輸出到頁面,但在express中,我們只需要對目錄進行簡單的靜態處理即可(首先建立一個public目錄,裡面放置一些資原始檔方便試驗),我們只需要在剛才的檔案中使用這個一個api即可:
//對目錄進行靜態資源處理,並使用
app.use('/public',express.static('./public'));
訪問結果:
相關說明
- express僅用了一個api就完成了http中需要進行相關判斷的操作,且不需要手動建立fs模組來讀取檔案。
express.static('路徑')
可以將路徑轉換為可通過url直接訪問的靜態資原始檔。app.use('url訪問路徑',靜態資原始檔)
是設定靜態資源訪問的路徑,如果不設定預設為/
。
更多有關Express的使用請參考下一篇文章。