JS 重構購物車案例 理解AJAX前後端傳輸數據的解碼編碼以及AJAX事件(node做後端)
- 2022 年 1 月 26 日
- 筆記
- javascript
AJAX簡介
首先我們來看w3c給的示例圖
在我工作中,用的最多的也是用來傳輸JSON數據,像官網介紹的這樣,Ajax 允許通過與場景後面的 Web 服務器交換數據來異步更新網頁。這意味着可以更新網頁的部分,而不需要重新加載整個頁面,這也是ajax的核心,了解以後那我們來簡單的寫一個AJAX的步驟
AJAX基本步驟
<script>
let times = 0;
let xhr = new XMLHttpRequest();
xhr.addEventListener( "readystatechange", readyStateChangeHandler );
xhr.addEventListener( "timeout", timeoutHandler );
xhr.open();
xhr.timeout = 2000;
xhr.send();
function readyStateChangeHandler( e ) {
if ( this.readyState === 4 && this.states === 200 ) {
console.log( this.response )
}
}
function timeoutHandler( e ) {
this.abort();
times++;
sendAJAX();
}
</script>
接下來我們一步步去理解其中的含義
我們先來用node寫一個server.js作為我們的後端
server
//加載庫中http.js,加載進入賦值給變量http,是一個對象
var http = require('http');
//req就是客戶端向服務器端請求的數據
//res就服務器項客戶端發送的數據
//http.createServer創建服務
var server = http.createServer(function (req, res) {
//客戶端請求的數據正在接收中的事件
req.on('data', function (d) {
console.log(d);
});
//客戶端請求的數據接收完成的後事件
req.on('end', function () {
//寫入頭部信息,允許傳輸任意文本信息,並且允許任意域訪問
res.writeHead(200, { 'Content-Type': 'text/plain', 'Access-Control-Allow-Origin': '*' });
res.write();
res.end();
});
});
server.listen(3002, '10.9.170.152', function () {
console.log('服務開啟,開始偵聽');
});
那麼基礎的步驟寫好了,別急,我們一步一步來慢慢完善我們的代碼
解碼以及編碼
我們在發送數據的時候,我們也不知道我們會遇到怎樣的後端,那他這個數據到底有沒有經過加碼呢,同樣的,我們將數據發給後端的時候我們要不要經過加碼呢,然後後端接受
到我們的數據以後需要先進行解碼,所以我們在不知道的情況下,我們默認就是
var xhr = new XMLHttpRequest();
xhr.addEventListener( "load", loadHandler );
var str = encodeURIComponent( "name=王大鎚" );
xhr.open( "get", "//192.168.0.103:3002?" + str );
// xhr.setRequestHeader("Content-Length","200");
// 將所有的URI編碼格式解碼為中文
console.log( decodeURIComponent( str ) );
// 將所有的中文轉換為URI編碼格式
console.log( encodeURIComponent( str ) );
xhr.send();
// 如果長時間沒有響應我們需要使用abort來關閉當前的AJAX通信
// xhr.abort();
function loadHandler( e ) {
console.log( decodeURIComponent( this.response ) );
}
那我們的打印出來的就是這樣的
這種通常用在get發送的時候,
var obj = JSON.parse(decodeURIComponent(data));
這裡呢還有一個知識點,經常用起來的時候就忘了~~~
在JS中,通過JSON.stringify()
方法,可以將JSON對象轉化為JSON字符串;通過JSON.parse()
方法,可以將JSON字符串轉化為JSON對象
發送JSON數據
好了,那麼了解了中文的解碼以及編碼以後,那我們拿到我們之前寫的購物車那組數據,那組數據里我們是有中文的,我們嘗試用post來發送數據,
我們現在有個需求,後端拿到我們數據以後,把裏面的num都加+1,然後再返回給我們
<script>
var data = [ {
id: 1001,
icon: "img/1.png",
name: "餐飲0",
num: 1,
price: 10
},
{
id: 1002,
icon: "img/2.png",
name: "餐飲1",
num: 1,
price: 20
},
{
id: 1003,
icon: "img/3.png",
name: "餐飲2",
num: 1,
price: 30
},
{
id: 1004,
icon: "img/4.png",
name: "餐飲3",
num: 1,
price: 40
},
{
id: 1005,
icon: "img/5.png",
name: "餐飲4",
num: 1,
price: 50
},
{
id: 1006,
icon: "img/6.png",
name: "餐飲5",
num: 1,
price: 60
},
{
id: 1007,
icon: "img/7.png",
name: "餐飲6",
num: 1,
price: 70
},
{
id: 1008,
icon: "img/8.png",
name: "餐飲7",
num: 1,
price: 80
},
{
id: 1009,
icon: "img/9.png",
name: "餐飲8",
num: 1,
price: 90
},
{
id: 1010,
icon: "img/10.png",
name: "餐飲9",
num: 1,
price: 100
}
];
var xhr = new XMLHttpRequest();
xhr.addEventListener( "load", loadHandler );
xhr.open( "POST", "//192.168.0.103:3002" );
xhr.send( encodeURIComponent( JSON.stringify( data ) ) );
function loadHandler( e ) {
console.log( JSON.parse( decodeURIComponent( this.response ) ) );
}
</script>
我們在後端接受到以後也要做處理,讓我們來看一下我們的server.js
var http = require('http');
var server = http.createServer(function (req, res) {
var data = '';
req.on('data', function (d) {
data += d;
});
req.on('end', function () {
//獲取請求頭
var obj = JSON.parse(decodeURIComponent(data));
obj.map(function (t) {
t.num++;
});
//writeHead()寫入請求頭
res.writeHead(200, { 'Content-Type': 'text/html', 'Access-Control-Allow-Origin': '*' });
//服務器發送數據時,最後發送時編碼
res.write(encodeURIComponent(JSON.stringify(obj)));
res.end();
});
});
server.listen(3002, '192.168.0.103', function () {
console.log('開啟服務');
});
接下來我們開啟服務
那麼我們在前端將會收到返回的數據,我們打開看看
好了,我們的效果已經實現了,綜上呢,我們就完成了數據傳給後端,後端修改完再傳給我們這樣的一個過程
AJAX的事件
接下來我們深入研究下ajax當中的readystatechange事件機制以及完整的寫法
那我們繼續把我們之前的data數據拿過來使用一下
如果我們這樣直接執行,會發生什麼問題,我們來打開瀏覽器看一下
可以看到先報了一堆錯,然後再去執行,我們可以看一下一共執行了4次,那麼這4次過程中,我們有四種不同的情況
我們打印一下xhr看看
這裡顯示的4,我們先不管他,因為他是個對象,對象屬性會動態改變,我們刷新一下,並且打印一下,console.log(xhr.readyState)看看
這裡代表我們通信道哪一步了,這裡看到進行到第一步了
readyState狀態
這裡不得不說一下我們的readyState的五個狀態
值 狀態 描述
0 UNSENT 代理被創建,但是尚未調用open的方法
1 OPENED open()方法已經被調用
2 HEADERS_RECEIVED send()方法已經被調用,並且頭部和狀態已經獲得
3 LOADING 下載中,responseText 屬性已經包含部分數據
4 DONE 下載操作完成
這裡是五種,不是四種,最早的這種的話,我們的偵聽就要放在new之前,基本沒什麼大用
status狀態改變
我們接着打印一下xhr這個對象下面的status看看
可以看到他代表了我們的狀態的改變,在第一步的時候的時候他是0,下載結束以後他的狀態改變為200,代表成功
常見的狀態碼還有常見的404,502等等
那麼我們接下來完善我們的ajax
完善AJAX
接着上面的需求,也就回到了我們首文,我們繼續改進這個需求,把購物車的數據返回給後端,修改num為2,然後再把數據返回給我們
這時候我們需要在下面調用ajax,所以為了防止代碼重複,我們把ajax寫入函數,然後調用它
這裡也要用到我們的timeout,寫在send之前,設定一個時間,如果過了這個時間還沒有接收到,那麼他就是超時
<script>
let data = [ {
id: 1001,
icon: "img/1.png",
name: "餐飲0",
num: 1,
price: 10
},
{
id: 1002,
icon: "img/2.png",
name: "餐飲1",
num: 1,
price: 20
},
{
id: 1003,
icon: "img/3.png",
name: "餐飲2",
num: 1,
price: 30
},
{
id: 1004,
icon: "img/4.png",
name: "餐飲3",
num: 1,
price: 40
},
{
id: 1005,
icon: "img/5.png",
name: "餐飲4",
num: 1,
price: 50
},
{
id: 1006,
icon: "img/6.png",
name: "餐飲5",
num: 1,
price: 60
},
{
id: 1007,
icon: "img/7.png",
name: "餐飲6",
num: 1,
price: 70
},
{
id: 1008,
icon: "img/8.png",
name: "餐飲7",
num: 1,
price: 80
},
{
id: 1009,
icon: "img/9.png",
name: "餐飲8",
num: 1,
price: 90
},
{
id: 1010,
icon: "img/10.png",
name: "餐飲9",
num: 1,
price: 100
}
];
let times = 0;
function sendAJAX() {
let xhr = new XMLHttpRequest();
xhr.addEventListener( "readystatechange", readyStateChangeHandler );
xhr.addEventListener( "timeout", timeoutHandler );
xhr.open( "post", "//192.168.0.103:3002" );
xhr.timeout = 2000;
xhr.send( encodeURIComponent( JSON.stringify( data ) ) );
}
function readyStateChangeHandler( e ) {
// console.log(xhr.readyState);
// console.log(xhr.status);
if ( this.readyState === 4 && this.status === 200 ) {
console.log( JSON.parse( decodeURIComponent( this.response ) ) );
}
}
function timeoutHandler( e ) {
//如果超時了,我們先終止請求,然後重新發起請求,下面我設置了請求三次,三次都沒有回應,那我們便return出去
this.abort();
times++;
if ( times > 2 ) {
return;
}
sendAJAX();
}
</script>