1. Node開發概述
1.1 為什么要學習服務器端開發基礎
- 能夠和后端程序員更加緊密的配合
- 網站業務邏輯前置,學習前端技術需要后端技術支持(Ajax)
- 擴寬知識視野,能夠站在更高的角度審視整個項目
1.2 服務器端開發要做的事情
- 實現網站的業務邏輯 比如登錄
- 數據的增刪改查 比如電商平台的購物車
1.3 為什么選擇Node
- 使用JavaScript語法開發后端應用
- 一些公司要求前端工程師掌握Node開發
- 生態系統活躍,有大量開源庫可以使用
- 前端開發工具大多基於Node開發
1.4 Node是什么
Node是一個基於Chrome V8引擎的JavaScript代碼運行環境
Chrome V8引擎: JavaScript代碼執行引擎。
1.5 Node.js 組成
- JavaScript由三部分組成,ECMAScript DOM BOM 其中ECMAScript是核心 DOM BOM是瀏覽器這個運行環境為JavaScript這個語言提供的api
- nodejs是由ECMAScript及node環境提供的一些附加api組成
1.6 Node.js 模塊化開發
JavaScript開發的弊端:文件依賴和命名沖突
所以需要模塊化,需要的開放出去 不需要的封裝掉
軟件中的模塊化開發:一個功能就是一個模塊,多個模塊可以組成完整應用,抽離一個模塊不會影響其他功能的運行。
比如:
app.js
user.js post.js goods.js
addUser.js deleteUser.js findGood.js addGood.js
node.js 規定一個js文件就是一個模塊,模塊內部定義的變量和函數默認情況下載外部無法得到
exports對象進行成員導出,使用require方法導入其他模塊
exports.version = version; exports.sayhi = sayhi; // b.js let a = require('./b.js'); console.log(a.version);
module.exports.version = version;
底層理解 exports 和 module.exports 都是對象,指向同一地址空間,如果不同的話,以module.export為准
1.7 系統模塊fs 文件操作
const fs = require('fs');
讀取文件內容:
fs.readFile('文件路徑/文件名稱'[,'文件編碼'],callback);
fs.readFile('../css/main.css','utf-8',(err,doc) => { // 如果文件讀取發生錯誤,參數err的值為錯誤對象,否則err為null // doc參數為文件內容 if(err ==null){ } })
node 中所有的回調函數第一個參數都是error。錯誤優先的回調函數
寫入文件:
fs.writeFile('文件路徑/文件名稱','數據',callback)
例如項目中寫入錯誤日志。
const content = ''; fs.writeFile('../index.html',content,err => { if(err != null){ console.log(err); return; } console.log('文件寫入成功'); })
系統模塊 path 路徑操作:
為什么要進行路徑拼接??
- 不同操作系統的路徑分隔符不統一
- Windows是 \ /
- Linux是/
- Linux系統通常被用作網站的服務器
比如 圖片上傳功能 存在服務器的某一個硬盤文件夾
路徑拼接語法:
path.join('路徑','路徑',...)
相對路徑 vs 絕對路徑:
- 大多數情況下使用絕對路徑,寫相對路徑不安全
- 因為執行的時候一般是當前工作目錄,所以相對路徑不安全
- 使用__dirname(兩個下划線)獲取當前目錄所在絕對路徑。
- require時相對路徑是相對當前目錄,所以require可以使用相對路徑
1.8 第三方模塊
包,第三方模塊,多個文件組成並在一個文件夾中
存在形式
- js文件,提高項目具體功能API接口
- 命令行工具存在
獲取第三方模塊:
npmjs.com 第三方模塊的存儲和分發倉庫
npm (node package manager): node 第三方模塊管理工具
- npm install
- npm uninstall
本地安裝和全局安裝
- 命令行工具:全局安裝
- 庫文件:本地安裝
1.9 第三方模塊 nodemon
在nodejs中每次修改文件都要在命令行中重新執行該文件,非常繁瑣
- npm install nodemon -g 下載 全局安裝
- 在命令行工具中使用nodemon命令代替node執行
- 用 ctr+C退出
1.10 第三方模塊 nrm
nrm (npm registry manager): npm下載地址切換工具
- npm install nrm -g
- 查詢 nrm ls
- 切換 nrm use 下載地址名稱
1.11 第三方模塊 Gulp
基於node平台開發的前端構建工具
將機械化操作編寫成任務,想要執行機械化操作時執行一個命令行命令任務就能自動執行了
用機器代替手工,提高開發效率
- npm install gulp 下載gulp庫文件
- 在項目根目錄下建立 gulpfile.js
- 重構項目的文件夾結構 src目錄放源代碼 dist目錄放構建后文件
- 在gulpfile.js中編寫任務
- 命令行工具中執行任務
1.12 package.json文件
package.json的作用:
項目描述文件,記錄了當前項目信息,例如項目名稱、版本、作者,github地址,當前項目依賴了哪些第三方模塊等。使用npm init -y
命令生成(y是全部默認值 (yes))
{ "name": "test", "version": "1.0.0", "description": "test main是項目主入口文件 scripts是命令的別名 ISC是開發源代碼協議", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "build":"nodemon app.js" }, "keywords": [], "author": "Jiaqi Guo", "license": "ISC" }
在終端寫npm run build可以執行nodemon app.js命令
項目依賴——線上線下都需要
開發依賴——開發階段需要依賴,線上運營階段不需要依賴的第三方包 使用npm install xxx --save -dev將包添加在package.json文件中的DevDependencies字段中, 比如 gulp
npm install 下載所有的依賴
npm install --production 服務器環境 下載項目依賴
package-lock.json
記錄模塊之間的依賴關系
1.13 Node.js 中模塊的加載機制
模塊查找規則:
require('./find.js');
require('./find');
- require方法根據模塊路徑查找模塊,如果是完整路徑,直接引入模塊
- 如果模塊后綴省略,先找同名js文件再找同名js文件夾
- 如果找到了同名文件夾,找文件夾中的index.js
- 如果文件夾中沒有index.js 就找當前文件夾package.js中找main選項的入口文件
- 如果入口文件不存在或者沒有則報錯,模塊沒有被找到。
模塊沒有路徑也沒有后綴
- 系統模塊
- 去node_modules文件夾中
- 首先看是否有改名字的js文件
- 文件夾
- 如果是文件夾看是否有index.js
- 如果沒有index.js看文件夾中package.json的main選項確定模塊入口文件
- 否則找不到報錯
2.Node運行環境搭建
2.1 Node.js運行環境安裝
官網:https://nodejs.org/en/
中文網:http://nodejs.cn/
關於版本:
LTS = Long Term Support 長期支持版 穩定版
Current 擁有最新特性 實驗版
運行中輸入:powershell 打開命令行工具
再輸入:node -v 可以查看安裝版本
2.2 Node環境安裝失敗的解決辦法
1.錯誤代號2502、2503
失敗原因:系統帳戶權限不足。
解決辦法:
1)以管理員身份運行 powershell 命令行工具
2)輸入運行安裝包命令 msiexec /package node安裝包位置。比如:msiexec /package E:\tools\node-v12.16.2-x64.msi
2.執行命令報錯
失敗原因:Node安裝目錄寫入環境變量失敗
解決辦法:將Node安裝目錄添加到環境變量中
2.3 PATH 環境變量
存儲系統中的目錄,在命令行中執行命令的時候,系統會自動去這些目錄中查找命令的位置。
3 Node.js 快速入門
3.1 Node.js 的組成
JavaScript 由三部分組成,ECMAScript、DOM、BOM。
Node.js 是由 ECMAScript 及 Node 環境提供的一些附加 API 組成的,包括文件、網絡、路徑等等一些更加強大的 API。
3.2 Node.js 基礎語法
所有 ECMAScript 語法在 Node 環境中都可以使用。
運行js文件:在文件當前目錄下,輸入:
node xxx.js
3.3 Node.js 全局對象 global
在瀏覽器中全局對象是 window,在 Node 中全局對象是 global。
Node 中全局對象下有以下方法,可以在任何地方是有,global 可以省略:
console.log() 在控制台輸出
setTimeout() 設置超時定時器
clearTimeout() 清除超時定時器
setInterval() 設置間歇定時器
clearInterval() 清除間歇定時器
例子:新建 global.js 文件:
global.console.log('我是global對象下面的console.log方法輸出的內容'); global.setTimeout(function () { console.log('123'); }, 2000)
在命令行工具中,輸入:
node global.js
結果是:先輸出“我是global對象下面的console.log方法輸出的內容”,然后2秒后輸出“123”。
修改下代碼,把 global 去掉:
console.log('我是global對象下面的console.log方法輸出的內容'); setTimeout(function () { console.log('123'); }, 2000)
在命令行工具輸入:
node global.js
結果和上面是一樣的,說明 global 是全局對象。
4 Node.js模塊化開發
4.1 JavaScript 開發弊端
JavaScript 在使用時存在兩大問題:文件依賴和命名沖突。
4.2 軟件中的模塊化開發
一個功能就是一個模塊,多個模塊可以組成完整營養,抽離一個模塊不會影響其他功能的運行。
4.3 Node.js 中模塊化開發規范
Node.js 規定一個 JavaScript 文件就是一個模塊,模塊內部定義的變量和函數,默認情況下在外部無法得到。
模塊內部可以使用 exports 對象進行成員導出,使用 require 方法導入其他模塊。
4.4 模塊成員導出
例子:
// a.js // 在模塊內部定義變量 let version = 1.2; // 在模塊內部定義方法 const sayHi = name => `您好,${name}`; // 向模塊外部導出數據 exports.version = version; exports.sayHi = sayHi;
4.5 模塊成員的導入
例子:
// b.js // 在 b.js 模塊中導入模塊 a let a = require('./a.js') // 輸出 a 模塊中的 version 變量 console.log(a.version); // 調用 a 模塊中的 sayHi 方法並輸出其返回值 console.log(a.sayHi('世界'));
此時在當面目錄下的命令行中,輸入:node ./b.js
會在控制台打印出:1.2 和 您好,世界
注意:導入模塊時后綴可以省略。
比如:在 b.js中 可以寫作
let a = require('./a')
4.6 模塊成員導出的另一種方式:
module.exports.version = version;
module.exports.sayHi = sayHi;
exports 是 module.exports 的別名(地址引用關系),導出對象最終以 module.exports 為准。
4.7 模塊導出兩種方式的聯系與區別:
當 exports 對象和 module.exports 對象,指向的不是同一個對象時,以 module.exports 為准。
5 系統模塊
5.1 什么是系統模塊
Node 運行環境提供的 API ,因為這些 API 都是以模塊化的方式進行開發的,所以我們又稱 Node 運行環境提供的 API 為系統模塊。
5.2 系統模塊fs 文件操作
f: file, s: system, fs: 文件操作系統
const fs = require('fs');
讀取文件內容:
fs.readFile('文件路徑/文件名稱'[,'文件編碼'],callback);
讀取文件語法示例:
// 讀取上一級 css 目錄下的 base.css fs.readFile('../css/base.css','utf-8', (err, doc) => { // 如果文件讀取法師錯誤,參數 err 的值為錯誤對象,否則 err 的值為 null // doc 參數為文件內容 if (err == null) { // 在控制台中輸入文件內容 console.log(doc); } });
例子:新建 readFile.js 文件:
// 1.通過模塊的名字 fs 對模塊進行引用 const fs = require('fs'); // 2.通過模塊內部的 readFile 方法,讀取文件內容 fs.readFile('./a.js','utf8', (err, doc) => { // 如果文件讀取法師錯誤,參數 err 的值為錯誤對象,否則 err 的值為 null // doc 參數為文件內容 if (err == null) { 在控制台中輸入文件內容 console.log(doc); } });
在當前目錄下的命令行輸入:node readFile.js
可以讀取出 a.js 的文件內容
寫入文件內容:
fs.writeFile('文件路徑/文件名', '數據', callback);
寫入文件語法示例:
const context = '<h3>正在使用fs.writeFile寫入文件內容</h3>'' fs.writeFIle('../index.html', context, err => { if (err != null) { console.log(err); return; } console.log('文件寫入成功'); });
例子:新建 writeFile 文件:
const fs = require('fs'); fs.writeFile('./demo.txt', '<h3>Hello world</h3>', err => { if (err != null) { console.log(err); return; } console.log('文件寫入成功'); })
注意:如果目錄下沒有 demo.txt 文件,系統會自動創建該文件;如果目錄下有 demo.txt 文件,那么會覆蓋替換原文件里面的內容。
此時,在當前目錄下的命令行輸入:node writeFile.js
命令行工具會顯示“文件寫入成功”,然后會看到目錄下生產一個 demo.txt 文件,里面的內容是“<h3>Hello world</h3>”。
5.3 系統模塊 path 路徑操作
為什么要進行路徑拼接:
不同操作系統的路徑分隔符不統一,比如:/public/upload/avatar
Windows 上是:\ 或 /
linux 上是:/
5.4 路徑拼接語法:
path.join('路徑', '路徑',
路徑拼接語法示例:
// 導入 path 模塊 const path = require('path'); // 路徑拼接 let finialPath = path.join('itcast', 'a', 'b', 'c.css'); // 輸出結果 itcast\a\b\c.css console.log(finialPath);
例子:新建 path.js 文件
// public/upload/avatar // 導入 path 模塊 const path = require('path'); // 路徑拼接 let finialPath = path.join('public', 'upload', 'avatar'); // 輸出結果 itcast\a\b\c.css console.log(finialPath);
此時,在當前目錄下的命令行輸入:node path.js
命令行工具會把拼接好的路徑打印出來。 public\upload\avatar
5.5 相對路徑 VS 絕對路徑
大多數情況下使用絕對路徑,因為相對路徑有時候相對的是命令行工具的當前工作目錄
在讀取文件或者設置文件路徑時都會選擇絕對路徑
使用 __dirname 獲取當前文件所在的絕對路徑
例子:新創建 path-xj.js 文件:
const fs = require('fs'); const path = require('path'); console.log(__dirname); // 獲取當前文件所在的絕對路徑 console.log(path.join(__dirname, 'helloa.js')); fs.readFile(path.join(__dirname, 'helloa.js'), 'utf8', (err, doc) => { console.log(err); console.log(doc); });
在命令行工具中,往上退一級目錄。
然后輸入:node .\desktop\path-xj.js
可以看到命令行工具中顯示:
6 第三方模塊
6.1 什么是第三方模塊
別人寫好的,具有特定功能的、我們能直接使用的模塊,即第三方模塊。由於第三方模塊通常都是由多個文件組成,並且被防止在一個文件夾中,所以又名包。
第三方模塊有兩種存在形式:
1)以 js 文件的形式存在,提供實現項目具體功能的 API 接口。
2)以命令行工具形式存在,輔助項目開發。
6.2 獲取第三方模塊
npmjs.com:第三方模塊的存儲和分發倉庫
npm(node package manager):node 的第三方模塊管理工具,包管理工具。
下載:npm install 模塊名稱
卸載:npm uninstall package 模塊名稱
全局安裝與本地安裝:
1)命令行工具:全局安裝
2)庫文件:本地安裝
6.3 第三方模塊 nodemon
nodemon 是一個命令行工具,用以輔助項目開發。可以監控文件的修改。
在 Node.js 中,每次修改文件都要在命令行工具中重新執行該文件,非常繁瑣。
使用步驟:
1)使用 npm install nodemon -g 下載
2)在命令行工具中使用 nodemon 命令替代 node 命令執行文件
6.4 第三方模塊 nrm
nrm(npm registry manager):npm 下載地址切換工具
使用步驟:
1)使用 npm install nrm -g 下載
2)查詢可用下載地址列表: nrm ls
3)切換 npm 下載地址:nrm use 下載地址名稱
安裝完成后,在命令行工具,輸入:
nrm ls
結果:
*代表的是 npm 當前默認下載地址。
切換淘寶的下載地址,在命令行輸入:
nrm use taobao
然后再輸入:
nrm ls
可以看到*切換到了 taobao 前面,表示 taobao 地址是當然默認地址了。
6.5 第三方模塊 Gulp
基於 node 平台開發的前端構建工具,主要用來設定程序自動處理靜態資源的工作。簡單的說,gulp就是用來打包項目的。
將機械化操作編寫成任務,想要執行機械化操作時執行一個命令行命令任務就能自動執行了。
用機器代替手工,提高開發效率。
中文官網:https://www.gulpjs.com.cn/docs/
7 package.json 文件
7.1 node_modules 文件夾的問題
1、文件夾以及文件過多過碎,當我們將項目整體拷貝給別人的時候,傳輸速度會很慢很慢。
2、復雜的模塊依賴關系需要被記錄,確保模塊的版本和當前保持一致,否則會導致當前項目運行報錯。
7.2 package.json 文件的作用
項目描述文件,記錄了當前項目信息,例如項目名稱、版本、作者、github地址、當前項目依賴了那些第三方模塊等。使用 npm init -y 命令生成。
例子:
1.先新建 description 文件夾,並在命令行工具中切換到 description 目錄下
輸入:(-y 表示 都用默認值)
npm init -y
效果圖:
會發現 description 目錄下,生成了 package.json 文件。
2.在命令行工具輸入:(可以同時安裝多個插件,以空格隔開)
npm install formidable mime
然后可以看到 package.json 文件,多了一個 dependencies 選項:
dependencies 就是項目所依賴的第三方模塊。
3.當我們把項目傳遞給別人時,不會傳遞 node_modules 文件夾。這里我們假設傳遞,把 node_modules 文件夾刪除掉
別人要做的就是,在命令行工具進入當前項目目錄,輸入:
npm install
npm 會自動到項目的根目錄下找 package.json 文件,然后這個文件中找到 dependencies 選項,再根據這個選項下載第三方模塊。
7.3 項目依賴
在項目的開發階段和線上運營階段,都需要依賴的第三方包,稱為項目依賴。
在 npm install 包名 命令下載的文件會默認被添加到 package.json 文件的 dependencies 字段中
{ "dependencies": { "jquery": "^3.3.1" } }
7.4 開發依賴
在項目的開發階段需要依賴,線上運營階段不需要依賴的第三方包,稱為開發依賴。
使用 npm install 包名 --save-dev 命令將包添加到 package.json 文件的 dependencies 字段中
{ "devDependencies": { "gulp": "^3.9.1" } }
例如:
npm install gulp --save-dev
package.json 文件中多了一個開發依賴devDependencies:
將項目依賴和開發依賴區分的好處是:可以在不同的運行環境,下載不同的依賴。
比如說在線下開發環境,可以在命令行工具輸入:npm install 下載所有依賴,
如果是在線上的運營環境(服務器環境),則可以輸入: npm install --production 只會下載 dependencies 選項的依賴。
scripts 選項:
在 package.json 文件中,scripts 選擇添加 build:
"scripts": { "test": "echo \"Error: no test specified\" && exit 1", "build": "nodemon app.js" },
在項目根目錄下新建 app.js 文件:
console.log('app.js 文件被執行了');
正常情況下,我們在命令行工具執行,輸入:
nodemon app.js
使用別名執行,輸入:
npm run build
使用別名語法:
npm run 別名
7.5 package-lock.json 文件的作用
package-lock.json 文件中包含:模塊與模塊之間的依賴關系,模塊的版本,模塊的下載地址
8 Node.js 中的模塊加載機制
8.1 模塊查找規則-當模塊擁有路徑但沒有后綴時
require('./find.js');
require('./find');
1、require 方法根據模塊路徑查找模塊,如果是完整路徑,直接引入模塊。
2、如果模塊的后綴省略,先找同名JS文件,再找同名JS文件夾
3、如果找到了同名文件夾,找文件夾中的 index.js
4、如果文件夾中沒有 index.js ,就會去當前文件夾中的 package.json 文件中查找 main 選項中的入口文件
5、如果找指定的入口文件補存在或者沒有指定入口文件,就會報錯,模塊沒有被找到。
例子:
新建項目 modulefindRules ,並創建 require.js 文件:
require('./find.js')
和 find.js 文件
console.log('modulefindRules 文件夾下的 find.js 被引用了');
在當然項目的命令行工具中輸入:
node require.js
效果圖:
修改 require.js 文件:
// require('./find.js') require('./find');
重新執行:
node require.js
發現結果和剛才是一樣的,同樣打印出了“modulefindRules 文件夾下的 find.js 被引用了”。
修改 find.js 文件名為 find1.js。
新建 find 文件夾,並創建 index.js 文件:
console.log('find 文件夾下的 index.js 被執行了');
這時在命令行工具輸入:
node require.js
打印的結果就是“find 文件夾下的 index.js 被執行了”。
在命令行工具中進入 find 目錄,然后輸入:
npm init -y
發現在 find 文件夾下,多了一個 package.json 文件,打開該文件,並把入口文件修改為:
"main": "main.js",
在 find 文件夾下,新建 main.js 文件:
console.log('find 文件夾下的 main.js 被執行了');
在命令行工具中返回到項目根目錄,重新輸入:
node require.js
發現打印的結果是:“find 文件夾下的 main.js 被執行了”。
8.2 模塊查找規則-當模塊沒有路徑且沒有后綴時
require('find');
1、Node.js 會假設它是系統模塊
2、Node.js 會去 node_modules 文件夾中
3、首先看是否有該名字的 JS 文件
4、再看是否 有該名字的文件夾
5、如果是文件夾看里面是否有 index.js
6、如果沒有 index.js,查看該文件夾中的 package.json 中的 main 選項確認模塊入口文件
7、否則找不到報錯
例子:
在根目錄下新建 node_modules 文件夾,並創建 find.js 文件:
console.log('node_modules 文件夾下的 find.js 被執行了');
回到命令行工具中,輸入:
node require.js
發現結果打印出“node_modules 文件夾下的 find.js 被執行了”。
把 node_modules 目錄下的 find.js 文件改名為:finde.js,並新建 find 文件夾,創建 index.js 文件:
console.log('node_modules 文件夾中的 find 文件夾下的 index.js 被執行了');
再回到命令行中輸入:
node require.js
此時的打印結果是:“node_modules 文件夾中的 find 文件夾下的 index.js 被執行了”。
修改 node_modules 文件夾中 find 文件夾下的 index.js 文件改名為:index2.js。
並在命令行工具中,進入 modulefindRules\node_modules\find 目錄,輸入:
npm init -y
然后在 modulefindRules\node_modules\find 目錄下,多了一個 package.json 文件,修改入口文件為:
"main": "b.js",
在 modulefindRules\node_modules\find 目錄下,新建 b.js 文件:
console.log('b.js 文件被執行了');
回到命令行工具的項目根目錄下,輸入:
node require.js
此時結果打印為:“b.js 文件被執行了”。