axios使用
先看看老朋友 axios
axios是基于Ajax+promise封装的
看一下他的简单使用
安装:npm install axios --save
引入:import axios from 'axios'
GitHub地址
基本使用
axios({url: 'http://hmajax.itheima.net/api/province'}).then(function (result) {
const {data: {list, message}, status} = result
console.log(list, message, status)
})
// 发送 GET 请求(默认的方法)
axios('/user/12345').then(response => {}).catch(error => {})
查询参数
axios({
url: 'http://hmajax.itheima.net/api/city',
method: 'get',
params: {
pname: '河南省'
}
}).then(function (result) {
// const {data: {list, message}, status} = result
console.log(result)
})
post提交
document.querySelector('button').addEventListener('click', function () {
axios({
url: 'http://hmajax.itheima.net/api/register',
method: 'post',
data: {
username: 'itheima123',
password: '123456'
}
}).then(function (result) {
console.log(result)
})
})
错误处理
document.querySelector('button').addEventListener('click', function () {
axios({
//请求选项
url: 'http://hmajax.itheima.net/api/register',
method: 'post',
data: {
username: 'itheima123',
password: '123456'
}
}).then(function (result) {
//处理数据
console.log(result)
}).catch(function (error) {
//处理错误
console.log(error.response.data.message)
})
})
实现一个简单地图片上传在这里插入图片描述
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
img {
height: 200px;
width: auto;
border-radius: 20px;
border: 1px solid rebeccapurple;
}
</style>
</head>
<body>
<input type="file" class="upload">
<img/>
</body>
<script type="text/javascript" src="../js/axios.js"></script>
<script type="text/javascript">
/*
* 图片上传显示在网页上面
* 1. 获取图片文件
* 2. 使用 FormData 携带图片文件
* 3. 提交到服务器获取到返回的图片服务器地址*/
document.querySelector('input').addEventListener('change', function (e) {
console.log(e.target.files[0])
//FormData对象
const fd = new FormData()
fd.append('img', e.target.files[0])
axios({
url: 'http://hmajax.itheima.net/api/uploadimg',
method: 'post',
data: fd
}).then(function (result) {
console.log(result)
document.querySelector('img').src = result.data.data.url
}).catch(function (error) {
console.log(error)
})
})
</script>
</html>
XMLhttpRequest使用
/*get请求携带参数*/
/*1. 实例化一个xhr对象*/
const xhr = new XMLHttpRequest()
/*2. 配置请求方法和URL地址*/
xhr.open('get', 'http://hmajax.itheima.net/api/city?pname=辽宁省')
/*3. 添加load事件,获取响应结果*/
xhr.addEventListener('load', function (result) {
console.log(JSON.parse(result.target.response))
document.write(JSON.parse(result.target.response).list.join(' , '))
})
/*4. 发起请求*/
xhr.send()
/*post请求设置请求头,携带请求体*/
document.querySelector('button').addEventListener('click', () => {
const xhr = new XMLHttpRequest()
xhr.open('post', 'http://hmajax.itheima.net/api/register')
xhr.addEventListener('load', function (result) {
console.log(JSON.parse(result.target.response))
})
/*设置请求头 告诉服务器 内容类型*/
xhr.setRequestHeader('Content-Type', 'application/json')
const user = {username: 'itheima093', password:' 123456'}
const userStr = JSON.stringify(user)
/*将字符串类型的 请求体发送给服务器*/
xhr.send(userStr)
})
详细文档参照 MDN
同步异步
- 同步代码
- 逐行执行,原地等待结果后,才继续向下执行
- 异步代码
- 调用后耗时,不阻塞代码执行,将来完成后触发回调函数
JavaScript中的异步代码有
- setTimeout / setInterval
- 事件
- Ajax
异步代码接收结果!
- 依靠异步的回调函数接收结果
回调地狱
在回调函数中一直向下嵌套回调函数,就会形成回调函数地狱
/*毁掉地狱*/
new MyAxios({
url: 'http://hmajax.itheima.net/api/province'
}).then(result => {
console.log(result)
let province = document.querySelector('.province')
province.innerHTML = result.list.map(item => `<option>${item}</option>`).join('')
new MyAxios({
url: 'http://hmajax.itheima.net/api/city',
params: {pname: province.value}
}).then(result => {
console.log(result)
let city = document.querySelector('.city')
city.innerHTML = result.list.map(item => `<option>${item}</option>`).join('')
new MyAxios({
url: 'http://hmajax.itheima.net/api/area',
params: {pname: province.value, cname: city.value}
}).then(result => {
console.log(result)
let area = document.querySelector('.area')
area.innerHTML = result.list.map(item => `<option>${item}</option>`).join('')
})
})
})
缺点:
- 可读性差
- 异常捕获困难
- 耦合性严重
解决:
promise的链式调用
使用then函数返回新的Promise对象的特性一直串联下去
/*链式调用*/
let province = document.querySelector('.province')
new MyAxios({url: 'http://hmajax.itheima.net/api/province'}).then(result => {
console.log(result);
province.innerHTML = result.list.map(item => `<option>${item}</option>`).join('')
return new MyAxios({url: 'http://hmajax.itheima.net/api/city', params: {pname: province.value}})
}).then(result => {
console.log(result);
let city = document.querySelector('.city');
city.innerHTML = result.list.map(item => `<option>${item}</option>`).join('')
return new MyAxios({url: 'http://hmajax.itheima.net/api/area', params: {pname: province.value, cname: city.value}})
}).then(result => {
console.log(result);
let area = document.querySelector('.area');
area.innerHTML = result.list.map(item => `<option>${item}</option>`).join('')
})
使用async 和 await解决(最优)
/*async await 配合使用*/
async function init() {
let province = document.querySelector('.province')
let city = document.querySelector('.city');
let area = document.querySelector('.area');
console.log('开始执行异步代码')
/*错误捕获; try 代码块中出现了错误,代码就不会继续往下执行了*/
try {
const provinceList = await new MyAxios({url: 'http://hmajax.itheima.net/api/province'})
province.innerHTML = provinceList.list.map(item => `<option>${item}</option>`).join('')
const cityList = await new MyAxios({url: 'http://hmajax.itheima.net/api/city', params: {pname: province.value}})
city.innerHTML = cityList.list.map(item => `<option>${item}</option>`).join('')
const areaList = await new MyAxios({url: 'http://hmajax.itheima.net/api/area', params: {pname: province.value, cname: city.value}})
area.innerHTML = areaList.list.map(item => `<option>${item}</option>`).join('')
console.log(provinceList)
console.log(cityList)
console.log(areaList)
}catch (error) {
console.dir(error)
}finally {
console.log('finally')
}
}
Promise
Promise 对象表示异步操作最终的完成(或失败)以及其结果值。
三个状态:
pending (初始状态,既没有兑现也没有拒绝) => fulfilled(操作成功) / rejected(操作失败)
Promise对象一旦被兑现或拒绝,就代表该对象就已敲定了,状态将无法在改变
优点:
- 逻辑更清晰
- 有助于了解axios的内部运作机制
- 解决回调函数地狱问题(通过链式调用 then 返回一个新的Promise对象
基本使用
/*使用promise管理异步任务*/
const p = new Promise((resolve, reject) => {
setTimeout(function () {
//resolve() => fulfilled状态-已兑现 => then()
// resolve('成功')
//reject() => rejected状态-已兑现 => catch()
reject(new Error('失败'))
}, 2000)
})
console.log(p)
p.then(result => {
console.log(result)
}).catch(error => {
console.log(error)
})
PromiseAll
/*当我们需要执行几个Promise对象,同时获取他们的结果时,使用Promise静态方法Promise.all([])*/
const ps = Promise.all([new Promise(resolve => resolve(1)), new Promise(resolve => resolve(2))])
// 这里的result是一个数组
ps.then(result => console.log(result))
const p1 = new Promise(resolve => resolve(3))
const p2 = new Promise(resolve => resolve(4))
const p3 = new Promise((resolve, reject) => {
reject('错误1')
})
const p4 = new Promise((resolve, reject) => {
reject('错误2')
})
// 当执行的过程中发生错误是,会中断执行并抛出第一个错误
Promise.all([p1, p2, p3, p4]).then(result => {
console.log(result)
}).catch(error => {
console.log(error)
})
Promise 配合 XMLHttpRequest使用
<script type="text/javascript">
const p = new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest()
xhr.open('get', 'http://hmajax.itheima.net/api/city?pname=湖南省')
xhr.addEventListener('loadend', function (result) {
if (result.target.status === 200) {
resolve(JSON.parse(xhr.response))
} else {
reject(new Error(xhr.response))
}
})
xhr.send()
})
console.log(p)
p.then(result => {
console.log('执行成功', result)
}).catch(error => {
//错误对象要是用console.dir详细打印
console.dir('执行错误', error)
})
</script>
XMLHttpRequest 配合 Promise进行简单封装和使用
// 封装为一个函数 MyAxios,返回的是一个Promise对象
function MyAxios({method = 'get', url, params, data}) {
//返回一个Promise对象
return new Promise((resolve, reject) => {
/*1. 实例化一个xhr对象*/
const xhr = new XMLHttpRequest()
/*判断是否有传参,有传参拼接在URL后面*/
url = params ? url + function () {
const keys = Object.keys(params)
const values = Object.values(params)
return '?' + keys.map((item, index) => item + '=' + values[index]).join('&')
}() : url
// console.log(url)
xhr.open(method, url)
// 有请求体,给请求头设置请求体文本类型
xhr.setRequestHeader('Content-Type', 'application/json')
/* 添加load事件,获取响应结果 */
xhr.addEventListener('loadend', function () {
/*200-300之间的状态码为响应成功状态码*/
if (xhr.status >= 200 && xhr.status < 300) {
/*返回的内容类型为JSON字符串,对它进行解析并返回*/
resolve(JSON.parse(xhr.response))
} else {
reject(new Error(xhr.response))
}
})
/*判断是否为post请求*/
data ? xhr.send(JSON.stringify(data)) : xhr.send()
})
}
/*get请求 传参*/
/*new MyAxios({
method: 'get',
url: 'http://hmajax.itheima.net/api/area',
params: {
pname: '河北省',
cname: '石家庄市'
}
}).then(result => {
console.log(result)
}).catch(error => {
console.log(error)
})*/
/*post请求*/
/*new MyAxios({
method: 'post',
url: 'http://hmajax.itheima.net/api/register',
data: {username: 'itheima095', password:' 123456'}
}).then(result => {
console.log(result)
}).catch(error => {
console.log(error)
})*/
/*获取城市天气*/
/*new MyAxios({
method: 'get',
url: 'http://hmajax.itheima.net/api/weather',
params: {
city: '110100'
}
}).then(result => {
console.log(result)
}).catch(error => {
console.log(error)
})*/
/*获取天气案例*/
document.querySelector('.search-city').addEventListener('input', debounce(fun, 500))
const ul = document.querySelector(`ul`)
function fun(e) {
console.log('发送请求', e.target.value)
new MyAxios({
url: 'http://hmajax.itheima.net/api/weather/city',
params: {
city: e.target.value
}
}).then(result => {
console.log(result)
ul.innerHTML = result.data.map(item => `<li data-code="${item.code}">${item.name}</li>`).join('')
}).catch(error => {
console.log(error)
})
}
ul.addEventListener('click', function (e) {
const li = e.target
if (li.tagName === 'LI') {
console.log(li.dataset.code);
new MyAxios({
method: 'get',
url: 'http://hmajax.itheima.net/api/weather',
params: {
city: li.dataset.code
}
}).then(result => {
console.log(result)
}).catch(error => {
console.log(error)
})
}
})
//防抖函数
function debounce(fun, delay = 500) {
let timer = null
return function (e) {
if (timer)
clearTimeout(timer)
timer = setTimeout(function () {
fun(e)
timer = null
}, delay)
}
}