AJAX

AJAX

基本概念

Asynchronous JavaScript And XML(异步的 JS 和 XML)

AJAX 是在不重新加载整个页面的情况下,与服务器交换数据并更新部分网页。(无刷新获取数据

优点与缺点

优点:

  1. 无需刷新页面与服务端通信

  2. 允许根据用户事件来更新部分页面内容

缺点:

  1. 没有浏览历史、不能回退
  2. 存在跨域问题
  3. 不易SEO

XMLHttpRequest

传统Ajax 指的是 XMLHttpRequest(XHR),最早出现的向后端发送请求的技术,隶属于原始 js 中

步骤

  • 创建对象 (XMLHttpRequest 对象)
  • 请求 (将请求发送到服务器,使用 XMLHttpRequest 对象的 open() 和 send() 方法)
  • 响应 (获得来自服务器的响应,使用 XMLHttpRequest 对象的 responseText 或 responseXML 属性)
  • 根据XMLHttpRequest的readyState判定调用哪个回调函数 (onreadystatechange 事件)
  • 更新页面

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
let xhr = new XMLHttpRequest();
// 请求成功回调函数
xhr.onload = e => {
console.log('request success');
};
// 请求结束回调函数
xhr.onloadend = e => {
console.log('request loadend');
};
// 请求出错回调函数
xhr.onerror = e => {
console.log('request error');
};
// 请求超时回调函数
xhr.ontimeout = e => {
console.log('request timeout');
};

xhr.timeout = 0; // 设置超时时间,0表示永不超时
// 初始化请求
xhr.open('GET/POST/DELETE/...', '/url', true || false);
// 设置期望的返回数据类型 'json' 'text' 'document' ...
xhr.responseType = '';
// 设置请求头
xhr.setRequestHeader('', '');
// 发送请求
xhr.send(null || new FormData || 'a=1&b=2' || 'json字符串');

// 请求回调函数
xhr.onreadystatechange = () => {
if (xhr.readyState === 4) {
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
console.log('request success');
} else {
console.log('request error');
}
}
};

// 取消请求
xhr.abort()

问题

浏览器通过 XMLHttpRequest 对象进行 http 通信,多个请求之间如果有先后关系的话,就会出现 回调地狱

fetch

fetch 号称是 AJAX 的替代品,是在 ES6 出现的,使用了ES6 中的 promise 对象。Fetch 是基于 promise 设计的。

fetch 不是 ajax的进一步封装,而是原生 JS , 没有使用 XMLHttpRequest 对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// 一个简单的fetch 请求
fetch('http://example.com/movies.json')
.then(function(response){
return response.json()
})
.then(function(myJson){
console.log(myJson)
})


// 一个带有参数的fetch请求
postData('http://example.com/answer',{answer: 42})
.then(data => console.log(data)) // JSON from 'response.json()' call
.catch(error => console.error(error))

function postData(url, data) {
// Default options are marked with *
return fetch(url, {
body: JSON.stringify(data), // must match 'Content-Type' header
cache: 'no-cache', // * default, no-cache, reload, force-cache, only-if-cached
headers: {
'user-agent': 'Mozilla/4.0 MDN Example',
'content-type': 'application/json'
},
method: 'POST', // *GET, POST, PUT, DELETE, etc.
mode: 'cors', // no-cors, cors, *same-origin
redirect: 'follow', // manual, *follow, error
referrer: 'no-referrer', // *client, no-referrer
})
.then(response => response.json()) // parses response to JSON

fetch 的优点:

  1、语法简洁,更加语义化

  2、基于标准 Promise 实现,支持 async / await

  3、同构方便,使用[isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)

  4、更加底层,提供的 API 丰富 (request, response)

  5、脱离了 XHR,是 ES 规范中新的实现方式。

缺点:

  1、fetch 只对网络请求报错,对400,500都当作成功的请求,服务器返回400, 500 错误码时并不会 reject,只有网络错误这些导致请求不能完成时, fetch 才会被 reject。需要封装去处理。

  2、fetch 默认不会带 cookie,需要添加配置项: fetch(url, {credentials: ‘include’})

  3、**fetch 不支持 abort** (xhr 有个 xhr.abort 方法可以直接阻断请求),不支持超时控制,使用 setTimeout 及 Promise.reject 的实现的超时控制并不能阻止请求,请求过程继续在后台运行,造成了流量的浪费。

  4、fetch 没有办法原生监测请求的进度,而 XHR 可以。

  5、fetch 兼容性并不太好,IE 不支持

axios

axios 是一个基于 Promise 的 http请求库,可以用在浏览器和 node.js 中,本质上也是对原生XHR的封装,只不过它是Promise 的实现版本,符合最新的ES规则。是目前最常用的请求方式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
import axios from 'axios'

// 配置 baseURL
axios.defaults.baseURL = 'http://localhost:8000';

// GET 请求
axios.get('/axios-server', {
// url 参数
params: {
id: 100,
vip: 7,
},
// 请求头信息
headers: {
name: 'atguigu',
age: 20,
}
}).then(value => {
console.log(value);
}).catch(error => {
console.log(error)
})

// POST 请求
axios.post('/axios-server', {
username: 'admin',
password: 'admin',
}, {
// url
params: {
id: 200,
vip: 9,
},
// 请求头参数
headers: {
height: 180,
weight: 180,
}
}).then(value => {
console.log(value);
}).catch(error => {
console.log(error)
})

// 通用
axios({
// 请求方法
method: 'POST',
//url
url: '/axios-server',
// url参数
params: {
vip: 10,
level: 30,
},
// 头信息
headers: {
a: 100,
b: 200,
},
// 请求体参数
data: {
username: 'admin',
password: 'admin',
}
}).then(response => {
console.log(response);
// 响应状态码
console.log(response.status);
// 响应状态字符串
console.log(response.statusText);
// 响应头信息
console.log(response.headers);
// 响应体
console.log(response.data);
}).catch(error => {
console.log(error)
})

// 利用 async await
async function getUser(){
try{
const response = await axios.get('/axios-server')
console.log(response)
}catch(error){
console.error(error)
}

axios 的特征:

  1、从浏览器中创建XMLHttpRequest

  2、支持 Promise API,不会产生回调地狱的问题

  3、客户端支持防止 CSRF

  4、提供了一些**并发**请求的接口(重要,方便了很多的操作)

  5、从 node.js 创建 http 请求

  6、拦截请求和响应

  7、转换请求和响应数据

  8、取消请求

  9、自动转换JSON数据

xhr 封装 axios

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function axios(method, url, data) {
return new Promise((resolve, reject) => {
let xhr = new XMLHttpRequest()
xhr.open(method, url)
xhr.send(data)
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
resolve(JSON.parse(xhr.response))
}
}
}
}

// 调用
axios('GET','接口地址').then(res=>{
console.log(res);
})

如何终止 http 请求

XMLHttpRequest

abort()

1
2
3
4
5
6
7
8
9
const ajax = XMLHttpRequest
ajax.open()
ajax.send()
ajax.onreadystateChange = () => {}

// 终止请求
setTimeout(() => {
ajax.abort()
}, 5000)

fetch

fetch需要配合AbortController实例来完成请求的取消

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
const controller = new AbortController();
let signal = controller.signal;

const downloadBtn = document.querySelector('.download');
const abortBtn = document.querySelector('.abort');

downloadBtn.addEventListener('click', fetchVideo);

abortBtn.addEventListener('click', function() {
controller.abort(); // 终止请求
console.log('Download aborted');
});

function fetchVideo() {
//...
fetch(url, {signal}).then(function(response) {
//...
}).catch(function(e) {
reports.textContent = 'Download error: ' + e.message;
})
}

axios

跟fetch有点像,使用CancelToken.source创建一个 cancel token 即可

1
2
3
4
5
6
7
8
9
10
const cancelToken = axios.CancelToken
const source = cancelToken.source()
axios.get(url, {
cancelToken: source.token
}).then(res => console.log(res))

// 终止请求
setTimeout(() => {
source.cancel()
}, 3000)

AJAX
http://example.com/2022/06/21/AJAX/
Author
John Doe
Posted on
June 21, 2022
Licensed under