本篇目標
- 能夠搭建 Node 運行環境
- 掌握 NodeJS 程序的運行方法
- 理解模塊化開發
- 理解系統模塊和第三方模塊
- 理解package.json文件作用
1.Node 開發概述
1.1為什么要學習服務器端開發技術
前端人員為什么要學習服務器端開發技術?
- 能夠和后端程序員更加緊密的配合
- 網站業務邏輯前置,學習前端技術需要后端技術支撐(Ajax)
- 擴寬知識視野,能夠站在更高的角度審視整個項目
1.2服務器端開發做什么
- 實現網站業務員邏輯
- 數據的增刪改查
1.3為什么選擇Node作為服務器技術
- 使用熟悉的js語法開發后端技術
- 很多一線城市公司的需求
- 生態系統活躍,有大量開源庫可以使用
- 前端開發工具大多基于Node開發
1.4Node是什么
Node官網
Node中文網
Node.js 是一個基于 Chrome V8 引擎的 JavaScript 運行時(運行環境),如瀏覽器也是js的運行環境,Node 也是JS的運行環境,但是將JS代碼的應用場景擴展到了服務器端
2.Node運行環境搭建
2.1安裝
打開 Node官網
如果不是你想要的版本,點擊頁面上的“DOWNLOADS” 鏈接,打開下載頁面
下載完成之后,雙擊安裝程序
下面以截圖的方式展現安裝過程,基本一路默認即可,需要注意的是安裝目錄不能是中文
安裝過程
注意:安裝完成后,桌面上并沒有什么快捷方式,因為Node僅僅是一個JS的執行環境
使用Node需要用到命令行工具
如何測試Node是否安裝成功呢?
打開命令行工具,這里可以使用傳統的 cmd 工具,也可以使用win10中的 powershell
我們這里使用后者
按下鍵盤上的 windows+S 鍵,輸入 powershell ,會搜索到powershell 工具
或者在任意位置,比如桌面,按下 shift 鍵同時,按下鼠標右鍵, 也會顯示 powershell 工具
打開命令行后,輸入如下命令
node -v
如果能夠顯示版本號,就表明node安裝成功
2.2環境安裝失敗解決辦法
2.2.1 錯誤代號 2502/2503
表示當前登錄系統的用戶權限不足。
解決方法:
- 以管理員身份運行 powershell 工具
- 屬于運行安裝包命令:msiexec /package node安裝包位置,如我安裝包在如下位置
則輸入如下命令進行安裝
2.2.2 環境變量問題
在 powershell 中輸入 node -v 時,會提示 node 不是可識別的命令類似的錯誤信息,原因在于,沒有將node可執行程序路徑添加到環境變量中
環境變量添加方法,這里不再演示
3. Node 入門
3.1 Node.js 組成
- JavaScript 由三部分組成,ECMAScript,DOM,BOM
- Node.js是由ECMAScript及Node 環境提供的一些附加API組成的,包括文件、網絡、路徑等等一些更加強大的 API
3.2 基礎語法和運行
首先,所有前面學習過的 ECMAScript 語法在Node中都可以使用,包括ES6的語法
3.2.1 運行node程序
那么,在Node環境下該如何執行我們的JS代碼呢?
按照如下步驟,我們開始第一個node程序的編寫和執行
-
打開任意你熟悉的開發工具,如sublime、vs code,或者記事本
-
新建文件 hello.js,注意這里的文件后綴名是 .js ,而不是 .html
-
編寫如下測試代碼
let ary = [12, 3, 4, 5] ary.forEach(item => console.log(item))
-
找到 hello.js 文件的位置,然后按下 shift 鍵的同事點擊鼠標右鍵,選擇“在此處打開powershell 窗口”
-
在命令行中輸入如下命令
node hello.js
敲擊回車鍵后,就可以執行 hello.js 中的代碼了
3.2.2 總結
通過上面代碼的編寫和執行,我們總結如下幾點
- node 文件的后綴名都是.js
- 以前的學習中,都是將js文件引入到html中,以運行html文件的方式執行js代碼,但node是服務器技術,在node技術中,不存在 dom 和 bom,所以運行方式與以前是不一樣的
- 運行node程序的方式是使用 node 命令加上文件名稱的方式
- 除了在命令行中運行node程序的方式外,很多開發工具,如vs code內部,也可以運行node程序
3.3 global
以前學習過,console 是 window 的全局對象,但是在 node 中,global 才是全局對象
Node中全局對象下有以下方法,可以在任何地方使用,global可以省略
- console.log() 在控制臺中輸出
- setTimeout() 設置超時定時器
- clearTimeout() 清除超時時定時器
- setInterval() 設置間歇定時器
- clearInterval() 清除間歇定時器
新建一個 global.js 文件,編寫下面代
global.setTimeout(() => {console.log('timeout')
}, 2000);
運行 global.js 文件,進行測試
證明,上面的這些API確實是全局對象 global 中的
4.模塊化開發
4.1 現有的弊端
在我們不算長的js代碼編寫經歷中,可能體會到或者體會不到,js開發有如下弊端
- 文件依賴:文件依賴不清楚,需要人為的去分析
- 命名沖突:兩個js文件中,可能存在同名的變量或者文件,會出現后面文件覆蓋掉前面文件的問題
舉例說明:
4.2 軟件中的模塊化開發
一個功能就是一個模塊,多個模塊可以組成完整應用,抽離一個模塊不會影響其他功能的運行
4.3 Node 中的模塊化開發規范
那么到底如何做到模塊化開發呢?
- Node.js規定一個JavaScript文件就是一個模塊,模塊內部定義的變量和函數默認情況下在外部無法得到
- 模塊內部可以使用exports對象進行成員導出, 使用require方法導入其他模塊。
注意:這里僅僅是Node中的模塊化開發規范,ES6也規定了自己的模塊化開發規范
代碼演示:
新建 m.js,編寫如下代碼
let name='李白'
var sum=(a,b)=>a+b
exports.name=name
exports.sum=sum
新建 n.js,編寫如下代碼
const m=require('./m.js')
console.log(m.dd)
console.log(m.ss(4,5))
運行 n.js ,可以看到結果
小編解惑
需要注意如下幾點
- 在n.js 中引入 m.js 時,可以省略后面的.js
- 引入 m.js 時,需要使用如下領“./m.js”
- m.js中,exports 后面的屬性名稱可以使用任何名稱
4.4 Node 中兩種模塊成員導出方法對比
exports.name=name
module.exports.name=name
上面案例用到了 exports.屬性=屬性值 的方式進行模塊成員導出
還可以使用 module.exports.屬性=屬性值 的方式進行模塊成員導出
總結:
exports是module.exports的別名(地址引用關系),導出對象最終以module.exports為準
下面證明這個結論
比如,在m.js 中編寫如下代碼
let name='李白'
let age=20
exports.name=name
module.exports.age=age
在 n.js 中編寫下面代碼
const m=require('./m.js')
console.log(m)
輸出結果
{ name: '李白', age: 20 }
課件,exports 與 module.exports 確實是一個地址,也就說最后修改的都是 module.exports
再次修改 m.js
let name='李白'
let age=20
module.exports.name=age
exports.name=name
再次運行 n.js
{ name: '李白' }
在 exports 和 module.exports 中都設置了name屬性,但一個將值設置成了 age 成員,一個設置成了 name 成員,最后發現還是以 module.exports 為準
這就證明了上面的結論
5.系統模塊
5.1 什么是系統模塊
Node運行環境提供的API. 因為這些API都是以模塊化的方式進行開發的, 所以我們又稱Node運行環境提供的API為系統模塊
小編解惑
在前面,我們學了很多JS的API,如 querySelector、getElementById、offsetLeft 等,這些都是瀏覽器提供的跟Dom或者Bom相關的功能,只不過這些API都是沒有任何關系的分散的。
Node 中,也提供了很多的API,但是將這些API根據烈性存放在不同的模塊中,如文件模塊中就包含了很多能夠操作磁盤文件的API
所以,我們可以總結如下:
- 所謂模塊化,就是將相關API根據類型劃分,存放到不同的文件中
- 系統模塊,就是 Node 預先已經定義好的一些API的集合
- 除了系統模塊,開發者還可以開發第三方模塊,其他開發者都可以使用,如我們前面自己定義的m.js也是一個第三方模塊
下面通過幾個系統模塊的講解,掌握 node 中代碼編寫的基本規則,以及模塊引入和使用的方法
5.2 文件操作
Node.js中文手冊
5.2.1 讀取文件
語法:
fs.readFile(path[, options], callback)
先看案例
const fs=require('fs')
fs.readFile('m.js','utf8',(err,data)=>{console.log(err)console.log(data)
})
小編解惑
- 系統模塊的引入方式也是使用 require
- 模塊名稱要使用引號包含起來
- readFile是一個異步方法,所以需要回調函數接收讀取結果
- 回調函數中,err 獲取讀取中的錯誤信息,如果讀取過程中沒有出現錯誤,則結果為null;data 為讀取的文件內容
所以一般在處理讀取的文件之前,先判斷err 的值
const fs = require('fs')
fs.readFile('m1.js', 'utf8', (err, data) => {if (err) throw err;console.log(data)
})
5.2.2 寫入文件
語法
fs.writeFile(file, data[, options], callback)
案例
const fs = require('fs')
fs.writeFile('./demo.txt', '說點什么呢', err => {if (err) throw err;console.log('文件寫入成功')
})
小編解惑
- 回調函數只有一個參數 err
5.3 路徑操作
5.3.1 路徑拼接
語法
path.join([...paths])
使用平臺特定的分隔符作為定界符將所有給定的 path
片段連接在一起,然后規范化生成的路徑。
小編解惑
因為不同平臺的路徑分隔符不統一,為了防止將路徑分隔符寫死,影響了程序的跨平臺特性,所以需要使用路徑拼接
案例
const path=require('path')
let res=path.join('public','static','images','time.jpg')
console.log(res)
windows 平臺運行結果
public\static\images\time.jpg
linux 平臺運行結果
public/static/images/time.jpg
5.3.2 使用相對路徑還是絕對路徑
- 大多數情況下使用絕對路徑,因為相對路徑有時候相對的是命令行工具的當前工作目錄
- 在讀取文件或者設置文件路徑時都會選擇絕對路徑
- 使用__dirname獲取當前文件所在的絕對路徑
代碼演示:
新建文件,編寫下代碼
const fs=require('fs')
fs.readFile('m.js','utf8',(err,data)=>{if(err) throw errconsole.log(data)
})
在此文件所在目錄中,打開命令行工具,并運行此文件,發現沒有問題
若在命令行工具中,使用如下命令,向上返回一級目錄
cd ..
再次執行命令
所以我們需要在代碼中,根據當前編寫的文件路徑,獲取絕對路徑,然后將文件路徑拼接成絕對路徑,就沒問題了
小編解惑
命令行工具目錄,就是你打開命令行工具時的目錄
如你在桌面上打開了命令行工具,那么目錄就是
如果在D盤根目錄下打開了命令函工具,那么目錄就是
但是在代碼編寫時,我們其實希望以當前正在編寫的文件為基礎作為相對路徑
6. 第三方模塊
別人寫好的、具有特定功能的、我們能直接使用的模塊即第三方模塊,由于第三方模塊通常都是由多個文件組成并且被放置在一個文件夾中,所以又名包。
第三方模塊有兩種存在形式:
- 以js文件的形式存在,提供實現項目具體功能的API接口,此種模塊多為本地安裝
- 以命令行工具形式存在,輔助項目開發,此種模塊多為全局安裝
6.1 如何獲取第三方模塊
https://www.npmjs.com/
開發者將開發好的第三方模塊,上傳到上面網站,其它開發者可以從上面下載
下載方式為命令行方式下載
下面是下載和卸載第三方模塊的基本語法
- 下載:npm install 模塊名稱
- 卸載:npm unintall package 模塊名稱
根據模塊的作用,分為全局安裝和本地安裝
- 本地安裝:模塊被下載到命令行工具所在目錄下,只能當前項目使用
- 全局安裝:模塊被下載全局目錄下,所有項目都可以使用
6.2 安裝演示
6.2.1 本地安裝
npm install jquery
安裝完成后,會在當前目錄下創建 node_modules 目錄
卸載
npm uninstall jquery
6.2.2 全局安裝
以 nodemon 模塊為例
nodemon是一個命令行工具,用以輔助項目開發。
在Node.js中,每次修改文件都要在命令行工具中重新執行該文件,非常繁瑣。
安裝
npm install nodemon -g
卸載
npm uninstall nodemon -g
6.2.3 安裝慢怎么辦
因為 npmjs.com 的服務器在國外,所有有時候下載速度很慢,或者總是斷開
解決方案就是更換下載源,最好是國內的下載源
解決方案有兩個
- 安裝 nrm,通過nrm更換下載源,更換之后,仍然使用 npm 命令安裝模塊
- 安裝 cnpm,以后通過cnpm 安裝,安裝后,使用 cnpm 安裝模塊
6.2.3.1 nrm
通過安裝 nrm 的方式,可以選擇和切換下載源
使用步驟
- 使用npm install nrm –g 下載它
- 查詢可用下載地址列表 nrm ls
- 切換npm下載地址 nrm use 下載地址名稱
- 下載模塊 npm install 模塊名稱
小編解惑
在鏡像源中,cnpm 和 taobao 其實是一樣的,所以選擇 taobao 還是 cnpm 都可以
6.3.2.2 cnpm
除了將下載地址切換為 cnpm 外,還可以直接安裝 cnpm
使用 npm 安裝 cnpm,同事將下載源更換為taobao
npm install -g cnpm --registry=https://registry.npm.taobao.org
安裝成功后,使用 cnpm 命令安裝第三方模塊,如
cnpm install jquery
說明:cnpm 只是基于npm 的一個小公舉
6.3 yarn
上面學習的 npm 是基于node.js 的一個包管理工具,除此之外,還有yarn,現在也非常流行
yarn 是現在非常流行的一個基于node.js的包管理工具,與 npm 可以說是雙雄爭霸
注意:yarn 與 cnpm 是不同的
6.3.1 yarn 安裝
yarn安裝
除了下載安裝包外,還可以從npm 中安裝yarn
下面使用 npm 包安裝 yarn(雖然yarn 是與npm 競爭關系,但是npm 還是和開放的允許安裝 yarn)
npm install yarn -g
執行下面命令,查詢yarn命令列表
yarh -h
查詢 yarn 版本
yarn -v
6.3.2 yarn 安裝和模塊
新建一個項目,然后打開命令行工具,執行如下命令
yarn add jquery
刪除模塊
yarn remove jquery
小編解惑
- 一個項目中,不要同事使用npm 和 yarn 進行包管理
- npm 和 yarn 的能力,我們僅僅使用了萬分之一,更多功能,后面再講
7. package.json 文件
7.1 node_modules 的問題
我們發現,當使用 npm 安裝模塊時,會創建 node_modules 目錄,此目錄中存儲下載的模塊及其依賴的模塊
這個目錄中的文件存在兩個問題
- 文件夾以及文件過多過碎,當將項目整體拷貝給別人時,傳輸速度很慢(事實上,node項目的體積主要就是node_modules)
- 復雜的模塊依賴關系需要被記錄,確保模塊的版本和當前保持一致,否則會導致當前項目運行報錯
7.2 package.json 解決問題
在個項目拷貝給他人時,刪除 node_modules,他人再使用 nmp 命令進行恢復安裝
這就需要一個文件能夠記錄,當前項目都使用了哪些模塊,這個文件就是 package.json
創建package.json
默認情況下,是沒有此文件的,可以使用命令生成此文件
新建項目,然后在此項目下打開命令行工具,運行如下命令
npm init -y
package.json 文件內容如下
{"name": "package_demo","version": "1.0.0","description": "","main": "index.js","scripts": {"test": "echo \"Error: no test specified\" && exit 1"},"keywords": [],"author": "","license": "ISC"
}
安裝模塊
npm install debug needle
觀察 package.json 文件變化
刪除node_modules
將項目拷貝給別人時,直接刪除 node_modules 目錄即可
恢復安裝
運行如下命令,即可根據package.json 中的記錄恢復安裝
npm install
7.3 項目依賴和開發依賴
- 項目依賴
- 在項目的開發階段和線上運營階段,都需要依賴的第三方包,稱為項目依賴
- 使用npm install 包名命令下載的文件會默認被添加到 package.json 文件的 dependencies 字段中
- 開發依賴
- 在項目的開發階段需要依賴,線上運營階段不需要依賴的第三方包,稱為開發依賴
- 使用npm install 包名 --save-dev命令將包添加到package.json文件的devDependencies字段中
案例演示:
使用如下命令安裝開發依賴包:gulp
npm install gulp --save-dev
查看package.json
刪除 node_modules 目錄
使用如下命令恢復項目依賴安裝
npm install --production
查看 node_modules 中的文件變化
再次刪除 node_modules,然后使用如下命令恢復開發依賴安裝
npm install
發現node_modules 中多了很多文件
8. package.lock.json
此文件在第一次使用npm下載模塊時就會被創建
作用如下:
- 鎖定包的版本,確保再次下載時不會因為包版本不同而產生問題
- 加快下載速度,因為該文件中已經記錄了項目所依賴第三方包的樹狀結構和包的下載地址,重新安裝時只需下載即可,不需要做額外的工作
9. 模塊加載規則
9.1 模塊擁有路徑時
分成下面兩種情況
require('./yhb.js') // 擁有路徑和后綴
require('./yhb') // 擁有路徑,但沒有后綴
- require方法根據模塊路徑查找模塊,如果是完整路徑,直接引入模塊
- 如果模塊后綴省略,先找同名JS文件再找同名JS文件夾
- 如果找到了同名文件夾,找文件夾中的index.js
- 如果文件夾中沒有index.js就會去當前文件夾中的package.json文件中查找main選項中的入口文件
- 如果找指定的入口文件不存在或者沒有指定入口文件就會報錯,模塊沒有被找到
9.2 沒有路徑
require('yhb')
- Node.js會假設它是系統模塊
- Node.js會去node_modules文件夾中
- 首先看是否有該名字的JS文件
- 再看是否有該名字的文件夾
- 如果是文件夾看里面是否有index.js
- 如果沒有index.js查看該文件夾中的package.json中的main選項確定模塊入口文件
- 否則找不到報錯
小編解惑
如果模塊沒有路徑,node會認為這是一個系統模塊
如果模塊擁有路徑,node會認為這是開發者自己定義的模塊文件