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>