AJAX
基本概念
Asynchronous JavaScript And XML(异步的 JS 和 XML)
AJAX 是在不重新加载整个页面的情况下,与服务器交换数据并更新部分网页。(无刷新获取数据)
优点与缺点
优点:
无需刷新页面与服务端通信
允许根据用户事件来更新部分页面内容
缺点:
- 没有浏览历史、不能回退
- 存在跨域问题
- 不易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;
xhr.open('GET/POST/DELETE/...', '/url', true || false);
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('http://example.com/movies.json') .then(function(response){ return response.json() }) .then(function(myJson){ console.log(myJson) })
postData('http://example.com/answer',{answer: 42}) .then(data => console.log(data)) .catch(error => console.error(error))
function postData(url, data) { return fetch(url, { body: JSON.stringify(data), cache: 'no-cache', headers: { 'user-agent': 'Mozilla/4.0 MDN Example', 'content-type': 'application/json' }, method: 'POST', mode: 'cors', redirect: 'follow', referrer: 'no-referrer', }) .then(response => response.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'
axios.defaults.baseURL = 'http://localhost:8000';
axios.get('/axios-server', { params: { id: 100, vip: 7, }, headers: { name: 'atguigu', age: 20, } }).then(value => { console.log(value); }).catch(error => { console.log(error) })
axios.post('/axios-server', { username: 'admin', password: 'admin', }, { params: { id: 200, vip: 9, }, headers: { height: 180, weight: 180, } }).then(value => { console.log(value); }).catch(error => { console.log(error) })
axios({ method: 'POST', url: '/axios-server', 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 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); })
|
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)
|