1 服務(wù)器開發(fā)的基本概念
1.1 為什么學(xué)習(xí)服務(wù)器開發(fā)
Node.js開發(fā)屬于服務(wù)器開發(fā),那么作為一名前端工程師為什么需要學(xué)習(xí)服務(wù)器開發(fā)呢?
為什么學(xué)習(xí)服務(wù)器開發(fā)?
- 能夠和后端程序員更加緊密配合
- 網(wǎng)站業(yè)務(wù)邏輯前置
- 擴(kuò)寬知識(shí)視野
1.2 服務(wù)器開發(fā)可以做哪些事情
- 實(shí)現(xiàn)網(wǎng)站的業(yè)務(wù)邏輯
- 實(shí)現(xiàn)數(shù)據(jù)的增刪改查
1.3 Node.js開發(fā)服務(wù)器的優(yōu)勢(shì)?
- Node.js是前端開發(fā)人員轉(zhuǎn)向后端開發(fā)人員的極佳途徑
- 一些公司要求前端工程師掌握Node.js開發(fā)
- Node.js生態(tài)系統(tǒng)活躍,有大量開源庫(kù)可以使用
- 前端開發(fā)工具大多基于Node.js開發(fā)
1.4 網(wǎng)站應(yīng)用程序的組成
一個(gè)完整的網(wǎng)站應(yīng)用程序主要由客戶端和服務(wù)器端兩大部分組成。
我們可以將服務(wù)器理解為一臺(tái)計(jì)算機(jī),主要負(fù)責(zé)存儲(chǔ)數(shù)據(jù)和處理應(yīng)用邏輯。
用Node.js來(lái)代替?zhèn)鹘y(tǒng)的服務(wù)端語(yǔ)言(如Java語(yǔ)言等),開發(fā)服務(wù)端的網(wǎng)站應(yīng)用。客戶端和服務(wù)器端網(wǎng)站開發(fā)流程:
2 Node.js網(wǎng)站服務(wù)器
2.1 初識(shí)Node.js網(wǎng)站服務(wù)器
Node.js網(wǎng)站服務(wù)器必須滿足以下3個(gè)條件
- 網(wǎng)站服務(wù)器必須是一臺(tái)計(jì)算機(jī);
- 計(jì)算機(jī)上需要安裝Node.js運(yùn)行環(huán)境;
- 使用Node.js創(chuàng)建一個(gè)能夠接收請(qǐng)求和響應(yīng)請(qǐng)求的對(duì)象。
網(wǎng)站服務(wù)器開發(fā)中涉及的一些基礎(chǔ)知識(shí)
- IP地址
- IP地址是互聯(lián)網(wǎng)中設(shè)備的唯一標(biāo)識(shí),代表互聯(lián)網(wǎng)協(xié)議地址。在計(jì)算機(jī)中,地址是由一串?dāng)?shù)字組成。
- 域名
- 域名平時(shí)上網(wǎng)所使用的網(wǎng)址。IP地址與域名是對(duì)應(yīng)的關(guān)系,在瀏覽器的地址欄中輸入域名,會(huì)有專門的服務(wù)器將域名解析為對(duì)應(yīng)的IP地址,從而找到對(duì)應(yīng)的服務(wù)器。
- 端口
- Node.js開發(fā)者習(xí)慣使用3000作為Node.js服務(wù)器的端口,一般來(lái)說(shuō),不使用0到1024之間的數(shù)字,因?yàn)檫@是操作系統(tǒng)軟件,以及常用軟件占用的端口。
- URL
- URL又叫統(tǒng)一資源定位符,它是專為標(biāo)識(shí)Internet網(wǎng)上資源位置而設(shè)的一種編址方式。
在開發(fā)階段,客戶端和服務(wù)器端使用同一臺(tái)計(jì)算機(jī),即開發(fā)人員計(jì)算機(jī)。
這是因?yàn)樵陂_發(fā)人員計(jì)算機(jī)中既安裝了瀏覽器(客戶端),又安裝了Node.js(服務(wù)器端)。既然是同一臺(tái)計(jì)算機(jī),我們?nèi)绾瓮ㄟ^(guò)網(wǎng)絡(luò)的方式訪問(wèn)它呢?
每臺(tái)計(jì)算機(jī)中都有一組特殊的IP和域名,代表本機(jī)。如果將本機(jī)作為服務(wù)器,則該計(jì)算機(jī)的特定IP為127.0.0.1,特定域名為localhost。
例如在開發(fā)程序中,我們輸入localhost就代表要通過(guò)網(wǎng)絡(luò)的方式找到自己計(jì)算機(jī)當(dāng)中的服務(wù)器。
2.2 創(chuàng)建Node.js網(wǎng)站服務(wù)器
在Node.js中創(chuàng)建網(wǎng)站服務(wù)器,并實(shí)現(xiàn)客戶端向服務(wù)器端發(fā)送請(qǐng)求,服務(wù)器端向客戶端做出響應(yīng)。
// 新建app.js文件
// 在test目錄下,新建app.js文件并編寫如下代碼
// 引用系統(tǒng)模塊
const http = require('http');
const app = http.createServer() // 創(chuàng)建Web服務(wù)器;
// 當(dāng)客戶端發(fā)送請(qǐng)求的時(shí)候
app.on('request', (req, res) => {
res.end('<h1>hi, user</h1>'); // 響應(yīng)
});
app.listen(3000); // 監(jiān)聽3000端口
console.log('服務(wù)器已啟動(dòng),監(jiān)聽3000端口,請(qǐng)?jiān)L問(wèn)localhost:3000');
// 打開命令行工具,切換到test目錄下,并輸入“nodemon app.js”命令。
// 在瀏覽器中輸入localhost:3000網(wǎng)址進(jìn)行訪問(wèn)。
3 HTTP協(xié)議
3.1 請(qǐng)求消息
請(qǐng)求方式用來(lái)規(guī)定客戶端與服務(wù)器端聯(lián)系的類型。HTTP協(xié)議中常用的請(qǐng)求方式有哪些?
主要是GET和POST兩種。
- 當(dāng)用戶在瀏覽器地址欄中直接輸入某個(gè)URL地址或者單擊網(wǎng)頁(yè)上一個(gè)超鏈接時(shí),瀏覽器將默認(rèn)使用GET方式發(fā)送請(qǐng)求。
- 如果將網(wǎng)頁(yè)上的標(biāo)簽的method屬性設(shè)置為post,那么就會(huì)以POST方式發(fā)送請(qǐng)求。
// app.js文件中找到res.end()方法,并在res.end()方法前面編寫如下代碼。
// 獲取請(qǐng)求方式
console.log(req.method);
在服務(wù)器收到GET請(qǐng)求和POST請(qǐng)求后,如何分開處理呢?
// 在app.on()中編寫處理請(qǐng)求的代碼
app.on('request', (req, res) => {
// 獲取請(qǐng)求方式
console.log(req.method);
if (req.method == 'POST') {
res.end('post');
} else if (req.method == 'GET') {
res.end('get');
};
// 響應(yīng)
// res.end('<hl>hi, user</hl>');
});
在實(shí)際應(yīng)用中,經(jīng)常通過(guò)單擊不同的鏈接進(jìn)入不同的頁(yè)面。
例如,在某個(gè)網(wǎng)站上,通過(guò)地址欄輸入不同的網(wǎng)址,會(huì)跳轉(zhuǎn)到相應(yīng)的頁(yè)面。這樣的需求常常需要在服務(wù)器端進(jìn)行請(qǐng)求處理。
Node.js中如何根據(jù)不同的URL 發(fā)送不同的響應(yīng)內(nèi)容?
// 創(chuàng)建 test 目錄,在該目錄下新建server.js文件
const http = require('http');
const app = http.createServer();
app.on('request', (req, res) => {
var url = req.url;
if (url == '/index' || url == '/') {
res.end('welcome to homepage');
} else if (url == '/list') {
res.end('welcome to listpage');
} else {
res.end('not found');
};
});
app.listen(3000);
console.log('服務(wù)器已啟動(dòng),監(jiān)聽3000端口,請(qǐng)?jiān)L問(wèn)localhost:3000');
// 打開命令行工具,切換到server.js文件所在目錄,執(zhí)行“node server.js”命令啟動(dòng)服務(wù)器。
3.2 響應(yīng)消息
在響應(yīng)消息中,對(duì)于客戶端的每一次請(qǐng)求,服務(wù)器端都有給予響應(yīng),在響應(yīng)的時(shí)候我們可以通過(guò)狀態(tài)碼告訴客戶端此次請(qǐng)求是成功還是失敗。
狀態(tài)代碼由3位數(shù)字組成,表示請(qǐng)求是否被理解或被滿足。HTTP響應(yīng)狀態(tài)碼的第一個(gè)數(shù)字定義了響應(yīng)的類別,后面兩位沒(méi)有具體的分類,第1位數(shù)字有5種可能的取值。
- 1**:請(qǐng)求已接收,需要繼續(xù)處理。
- 2**:請(qǐng)求已成功被服務(wù)器接收、理解并接受。
- 3**:為完成請(qǐng)求,客戶端需進(jìn)一步細(xì)化請(qǐng)求。
- 4**:客戶端的請(qǐng)求有錯(cuò)誤。
- 5**:服務(wù)器端出現(xiàn)錯(cuò)誤。
HTTP協(xié)議常見(jiàn)的狀態(tài)碼
狀態(tài)碼 | 說(shuō)明 |
---|---|
200 | 表示服務(wù)器成功處理了客戶端的請(qǐng)求 |
302 | 表示請(qǐng)求的資源臨時(shí)從不同的URI響應(yīng)請(qǐng)求,但請(qǐng)求者應(yīng)繼續(xù)使用原有位置來(lái)進(jìn)行以后的請(qǐng)求 |
404 | 表示服務(wù)器找不到請(qǐng)求的資源 |
400 | 表示客戶端請(qǐng)求有語(yǔ)法錯(cuò)誤 |
500 | 表示服務(wù)器發(fā)生錯(cuò)誤,無(wú)法處理客戶端的請(qǐng)求 |
響應(yīng)內(nèi)容類型
服務(wù)器端返回結(jié)果給客戶端時(shí),通常需要指定內(nèi)容類型(content-type屬性)
- text/plain:返回純文本格式
- text/html:返回HTML格式。
- text/css:返回CSS格式。
- application/javascript:返回JavaScript格式。
- image/jpeg:返回JPEG圖片格式。
- application/json:返回JSON代碼格式。
// 創(chuàng)建test目錄,在該目錄下新建server.js文件。
// 引用系統(tǒng)模塊
const http = require('http');
// 創(chuàng)建web服務(wù)器
const app = http.createServer();
// 當(dāng)客戶端發(fā)送請(qǐng)求的時(shí)候
app.on('request', (req, res) => {
res.writeHead(200, {
'content-type': 'text/plain'
});
// 響應(yīng)
res.end('<h1>hi, user</h1>');
});
// 監(jiān)聽3000端口
app.listen(3000);
console.log('服務(wù)器已啟動(dòng),監(jiān)聽3000端口,請(qǐng)?jiān)L問(wèn)localhost:3000');
// 將<h1></h1>中的英文內(nèi)容改為中文“歡迎”,再次刷新頁(yè)面。
// 此時(shí)標(biāo)簽可以正確顯示,但是中文會(huì)亂碼。
// 修改文件中的“content-type”項(xiàng)
res.writeHead(200, {
'content-type': 'text/html;charset=utf8'
});
4 HTTP請(qǐng)求與響應(yīng)處理
4.1 GET請(qǐng)求參數(shù)
GET參數(shù)被放置在瀏覽器地址欄中進(jìn)行傳輸。
// http://localhost:3000/index?name=zhangsan&age=20
// 請(qǐng)求參數(shù) name=zhangsan&age=20
// 在test目錄下,新建server.js作為服務(wù)器文件。
const http = require('http'); // 引用HTTP系統(tǒng)模塊
const app = http.createServer(); // 創(chuàng)建網(wǎng)站服務(wù)器
var url = require('url'); // 引用處理URL地址模塊
app.on('request', (req, res) => {
console.log(req.url); // 獲取整個(gè)URL中的資源具體地址
console.log(url.parse(req.url, true)); // 解析URL參數(shù)
let { query, pathname } = url.parse(req.url, true);
if (pathname == '/index' || pathname == '/') {
res.end('<h1>welcome to homepage<h1>');
} else if (pathname == '/list') {
res.end('welcome to listpage');
} else {
res.end('not found');
};
});
app.listen(3000);
console.log('服務(wù)器已啟動(dòng),監(jiān)聽3000端口,請(qǐng)?jiān)L問(wèn)localhost:3000');
// 回到命令行工具,切換到test目錄
// 輸入“nodemon server.js”命令啟動(dòng)服務(wù)器。
4.2 POST請(qǐng)求參數(shù)
POST請(qǐng)求參數(shù)被放置在請(qǐng)求體中進(jìn)行傳輸。
<!-- 在test目錄下,新建form.html文件。-->
<form method="post" action="http://localhost:3000">
<input type="text" name="username">
<input type="password" name="password">
<input type="submit" name="">
</form>
// 在test目錄下,新建post.js文件。
const http = require('http');
const app = http.createServer();
// 導(dǎo)入系統(tǒng)模塊querystring用于將POST請(qǐng)求參數(shù)轉(zhuǎn)換為對(duì)象格式
const querystring = require('querystring');
app.on('request', (req, res) => {
let postParams = '';
req.on('data', params => {
// 監(jiān)聽參數(shù)傳輸事件
postParams += params;
});
req.on('end', () => {
// 監(jiān)聽參數(shù)傳輸完畢事件
console.log(postParams);
console.log(querystring.parse(postParams));
});
res.end('ok');
});
app.listen(3000);
console.log('服務(wù)器已啟動(dòng),監(jiān)聽3000端口,請(qǐng)?jiān)L問(wèn)localhost:3000');
// 回到命令行工具,切換到test目錄,輸入“nodemon post.js”命令啟動(dòng)服務(wù)器
4.3 路由
用戶在瀏覽器地址欄中輸入不同的請(qǐng)求地址,服務(wù)器端會(huì)為客戶端響應(yīng)不同的內(nèi)容。
例如,客戶端訪問(wèn)“http://localhost:3000/index
”這個(gè)請(qǐng)求地址,服務(wù)器端要為客戶端響應(yīng)首頁(yè)的內(nèi)容,這是由網(wǎng)站應(yīng)用中的路由實(shí)現(xiàn)的。
路由是指客戶端請(qǐng)求地址與服務(wù)器端程序代碼的對(duì)應(yīng)關(guān)系。
// 在test目錄下,新建app.js文件。
const http = require('http'); // 引用系統(tǒng)模塊HTTP
const app = http.createServer(); // 創(chuàng)建網(wǎng)站服務(wù)器
const url = require('url');
app.on('request', (req, res) => { // 為網(wǎng)站服務(wù)器對(duì)象添加請(qǐng)求事件
const method = req.method.toLowerCase(); // 獲取客戶端的請(qǐng)求方式,
const pathname = url.parse(req.url).pathname; // 獲取請(qǐng)求地址
res.writeHead(200, { 'content-type': 'text/html;charset=utf8' });
// 實(shí)現(xiàn)路由功能
if (method == 'get') {
if (pathname == '/' || pathname == '/index') {
res.end('歡迎來(lái)到首頁(yè)');
} else if (pathname == '/list') {
res.end('歡迎來(lái)到列表頁(yè)');
} else {
res.end('您訪問(wèn)的頁(yè)面不存在');
}
} else if (method == 'post') {
// 請(qǐng)求方式為POST時(shí)的邏輯處理
}
});
app.listen(3000); // 監(jiān)聽3000端口
console.log('服務(wù)器已啟動(dòng),監(jiān)聽3000端口,請(qǐng)?jiān)L問(wèn)localhost:3000');
// 到命令行工具,切換到test目錄
// 輸入“nodemon app.js”命令啟動(dòng)服務(wù)器
4.4 靜態(tài)資源訪問(wèn)
靜態(tài)資源服務(wù)
靜態(tài)資源服務(wù)是指客戶端向服務(wù)器端請(qǐng)求的資源,服務(wù)器端不需要處理,可以直接響應(yīng)給客戶端的資源。
靜態(tài)資源主要包括CSS、JavaScript、image文件,以及HTML文件。
動(dòng)態(tài)資源指的是相同的請(qǐng)求地址可以傳遞不同的請(qǐng)求參數(shù),得到不同的響應(yīng)資源,這種資源稱為動(dòng)態(tài)資源。
實(shí)現(xiàn)靜態(tài)資源訪問(wèn)
靜態(tài)資源是存放在本地的,只能自己可以訪問(wèn)到,其他人不能訪問(wèn)。
如果希望服務(wù)器端的靜態(tài)資源能夠被用戶訪問(wèn)到,這就需要實(shí)現(xiàn)靜態(tài)資源訪問(wèn)功能。
在服務(wù)器端創(chuàng)建一個(gè)專門的目錄,存放靜態(tài)資源。
當(dāng)客戶端請(qǐng)求某個(gè)靜態(tài)資源文件時(shí),服務(wù)器端將這個(gè)靜態(tài)資源響應(yīng)給客戶端。
// 創(chuàng)建test目錄,在該目錄下新建public目錄,用于存放靜態(tài)文件。
// 啟動(dòng)服務(wù)器,在test目錄下創(chuàng)建app.js文件。
const http = require('http'); // 引用系統(tǒng)模塊HTTP
const app = http.createServer();// 用戶創(chuàng)建網(wǎng)站服務(wù)器
const url = require('url'); // 引用url地址模塊
const path = require('path'); // 引用系統(tǒng)模塊Path,用于讀取文件前拼接路徑
const fs = require('fs'); // 引用系統(tǒng)模塊Fs,讀取靜態(tài)資源
const mime = require('mime'); // 引用第三方模塊
// 為網(wǎng)站服務(wù)器對(duì)象添加請(qǐng)求事件
app.on('request', (req, res) => {
// 處理請(qǐng)求
// 獲取用戶請(qǐng)求路徑
let pathname = url.parse(req.url).pathname;
// 三元表達(dá)式,表達(dá)式 ? 表達(dá)式1 : 表達(dá)式2
pathname = pathname == '/' ? '/default.html' : pathname;
// 將用戶請(qǐng)求的路徑轉(zhuǎn)換為實(shí)際的服務(wù)器硬盤路徑
let realPath = path.join(__dirname, 'public' + pathname);
// 利用mime模塊根據(jù)路徑返回資源的類型
let type = mime.getType(realPath);
// 讀取文件
fs.readFile(realPath, (error, result) => {
if (error != null) { // 如果文件讀取失敗
// 指定返回資源的文件編碼
res.writeHead(404, { 'content-type': 'text/html;charset=utf8' });
res.end('文件讀取失敗');
} else { // 如果文件讀取成功
res.writeHead(200, {
'content-type': type
});
res.end(result);
};
});
});
// 監(jiān)聽3000端口
app.listen(3000);
console.log('服務(wù)器已啟動(dòng),監(jiān)聽3000端口,請(qǐng)?jiān)L問(wèn)localhost:3000');
// 打開命令行工具,切換到test目錄下,輸入“nodemon app.js”命令
5 Node.js異步編程
5.1 同步異步API的概念
Node.js中的一些API有的是通過(guò)返回值的方式獲取API的執(zhí)行結(jié)果,有的是通過(guò)函數(shù)的方式獲取結(jié)果,同步和異步兩種API有什么區(qū)別呢?
同步API
同步API指只有當(dāng)前API執(zhí)行完成后,才能繼續(xù)執(zhí)行下一個(gè)API。
舉例:到餐館點(diǎn)餐時(shí),一個(gè)指定的服務(wù)員被分配給你服務(wù),當(dāng)你點(diǎn)完餐時(shí),服務(wù)員將訂單送到廚房并在廚房等待廚師制作菜肴,當(dāng)廚師將菜肴烹飪完成后,服務(wù)員將菜肴送到你的面前,服務(wù)完成,此時(shí)這個(gè)服務(wù)員才能服務(wù)另外的客人。也就是說(shuō),一個(gè)服務(wù)員同時(shí)只能服務(wù)于一個(gè)客人。
異步API
異步API指當(dāng)前API的執(zhí)行不會(huì)阻塞后續(xù)代碼的執(zhí)行。
舉例:到餐館點(diǎn)餐時(shí),在點(diǎn)餐后服務(wù)員將你的訂單送到廚房,此時(shí)服務(wù)員沒(méi)有在廚房等待廚師烹飪菜肴,而是去服務(wù)了其他客人,當(dāng)廚師將你的菜肴烹飪好以后,服務(wù)員再將菜肴送到你的面前。也就是說(shuō),一個(gè)服務(wù)員同時(shí)可以服務(wù)多個(gè)客人。
同步API的執(zhí)行方式
同步API的執(zhí)行方式,代碼從上到下一行一行執(zhí)行,下一行的代碼必須等待上一行代碼執(zhí)行完成以后才能執(zhí)行。
console.log('before');
console.log('after');
異步API的執(zhí)行方式
異步API的執(zhí)行方式,代碼在執(zhí)行過(guò)程中某行代碼需要耗時(shí),代碼的執(zhí)行不會(huì)等待耗時(shí)操作完成以后再去執(zhí)行下一行代碼,而是不等待直接向后執(zhí)行。異步代碼的執(zhí)行結(jié)果需要通過(guò)回調(diào)函數(shù)的方式處理。
console.log('before');
setTimeout(() => {
console.log('last');
}, 2000);
console.log('after');
5.2 獲取異步API的返回值
同步API可以從返回值中拿到API執(zhí)行的結(jié)果,那么異步API的返回值是如何獲取的呢?
// 在test目錄下,新建callback.js文件。
// getMsg函數(shù)定義
function getMsg(callback) {
setTimeout(function () {
// 調(diào)用callback
callback({
msg: 'hello node.js'
});
}, 2000);
};
// getMsg函數(shù)調(diào)用
getMsg(function (data) {
console.log(data); // 在回調(diào)函數(shù)中獲取異步API執(zhí)行的結(jié)果
});
// 打開命令行工具,切換到callback.js所在目錄,執(zhí)行“node callback.js”命令
5.3 異步編程中回調(diào)地獄的問(wèn)題
什么是回調(diào)地獄
異步API不能通過(guò)返回值的方式獲取執(zhí)行結(jié)果,異步API也不會(huì)阻塞后續(xù)代碼的執(zhí)行。
如果異步API后面代碼的執(zhí)行依賴當(dāng)前異步API的執(zhí)行結(jié)果,這就需要把代碼寫在回調(diào)函數(shù)中。一旦回調(diào)函數(shù)的嵌套層次過(guò)多,就會(huì)導(dǎo)致代碼不易維護(hù),我們將這種代碼形象地稱為回調(diào)地獄。
回調(diào)地獄案例
依次讀取A文件、B文件、C文件。
通常的做法是:使用fs.readFile()方法讀取A文件,A文件讀取完成之后,在讀取A文件的回調(diào)函數(shù)中去讀取B文件;B文件讀取完成之后,在讀取B文件的回調(diào)函數(shù)中去讀取C文件。
// (1)test目錄下,創(chuàng)建3個(gè)文件,分別是1.txt、2.txt、3.txt。
// 其中,1.txt文件的內(nèi)容為1,2.txt文件的內(nèi)容為2,3.txt文件的內(nèi)容為3。
// (2)在test目錄下新建callbackhell.js文件。
const fs = require('fs');
fs.readFile('./1.txt', 'utf8', (err, result1) => {
console.log(result1);
fs.readFile('./2.txt', 'utf8', (err, result2) => {
console.log(result2);
fs.readFile('./3.txt', 'utf8', (err, result3) => {
console.log(result3);
});
});
});
// 打開命令行工具,切換到callbackhell.js所在目錄,執(zhí)行“node callbackhell.js”命令
5.4 利用Promise解決回調(diào)地獄
利用Promise解決回調(diào)地獄
Promise本身是一個(gè)構(gòu)造函數(shù),如果要使用Promise解決回調(diào)地獄的問(wèn)題,需要使用new關(guān)鍵字創(chuàng)建Promise構(gòu)造函數(shù)的實(shí)例對(duì)象。
// 定義Promise
let promise = new Promise((resolve, reject) => { });
// 定義resolve和reject參數(shù)函數(shù)
promise.then(result => console.log(result))
.catch(error => console.log(error));
// 在test目錄下新建promise.js文件。
const fs = require('fs');
function p1() {
return new Promise((resolve, reject) => {
fs.readFile('./1.txt', 'utf8', (err, result) => {
resolve(result);
});
});
}
function p2() {}
function p3() {}
p1().then((r1) => {
console.log(r1);
// 使用return返回p2()函數(shù)的Promise對(duì)象
// 會(huì)在下一個(gè)then()中拿到這個(gè)Promise對(duì)象的結(jié)果
return p2();
})
.then((r2) => {
// 獲取上一個(gè)Promise對(duì)象的結(jié)果
})
.then((r3) => {
// 獲取上一個(gè)Promise對(duì)象的結(jié)果
console.log(r3);
})
// 打開命令行工具,切換到promise.js所在目錄,執(zhí)行“node promise.js”命令。
5.5 異步函數(shù)
異步函數(shù)
異步函數(shù)實(shí)際上是在Promise對(duì)象的基礎(chǔ)上進(jìn)行了封裝,它把一些看起來(lái)比較繁瑣的代碼封裝起來(lái),然后開放一些關(guān)鍵字供開發(fā)者來(lái)使用。
異步函數(shù)是異步編程語(yǔ)法的終極解決方案,它可以讓我們將異步代碼寫成同步的形式,讓代碼不再有回調(diào)函數(shù)嵌套,使代碼變得清晰明了。
async關(guān)鍵字
異步函數(shù)需要在function前面加上async關(guān)鍵字。
async function fn() {
// throw代替reject()方法
throw '發(fā)生錯(cuò)誤';
// return代替resolve()方法
return 123;
}
fn().then(function (data) {
// 獲取到return的值123
console.log(data);
}).catch(function (error) {
// 捕獲throw的拋出錯(cuò)誤
console.log(error);
})
await關(guān)鍵字
await關(guān)鍵字可以暫停異步函數(shù)的執(zhí)行,等待Promise對(duì)象返回結(jié)果再向下執(zhí)行函數(shù)。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-727130.html
await關(guān)鍵字只能出現(xiàn)在異步函數(shù)中,await后面只能寫Promise對(duì)象,不能寫其他類型API。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-727130.html
// 使用await關(guān)鍵字實(shí)現(xiàn)3個(gè)異步函數(shù)的有序執(zhí)行
// 在test目錄下新建await.js文件。
async function p1() {return 'p1';}
async function p2() {return 'p2';}
async function p3() {return 'p3';}
async function run() {
let r1 = await p1();
let r2 = await p2();
let r3 = await p3();
console.log(r1);
console.log(r2);
console.log(r3);
}
run();
// 打開命令行工具,切換到await.js所在目錄,執(zhí)行“node await.js”命令
// 使用異步函數(shù)優(yōu)化前面編寫的promise.js文件中的代碼
// 在test目錄下新建async.js文件。
const fs = require('fs');
const promisify = require('util').promisify;
const readFile = promisify(fs.readFile);
async function run() {
let r1 = await readFile('./1.txt', 'utf8');
let r2 = await readFile('./2.txt', 'utf8');
let r3 = await readFile('./3.txt', 'utf8');
console.log(r1);
console.log(r2);
console.log(r3);
}
run();
// 打開命令行工具,切換到async.js所在目錄,執(zhí)行“node async.js”命令。
到了這里,關(guān)于06_Node.js服務(wù)器開發(fā)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!