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", "http://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", "http://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", "http://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>