
一、了解XMLHttpRequest 的基本用法
XHR 就是原生代码,在面试时大概率会问







二、数据交换格式
1. 什么是数据交换格式

2. 什么是 JSON

3. JSON 数据

3.1 对象格式的 JSON 格式

3.2 数组格式的 JSON 格式

4. JSON 的两个方法
4.1 JSON.parse()

4.2 JSON.stringify()

5. 序列化和反序列化

6. JSON 文件的语法要求


尝试:
三、Promise

1. 异步函数 和 回调函数

把function传给setTimeout()使用,所以这是一个回调函数
2. 回调地狱


2.1 回调函数的嵌套问题演示


3. promise 的基本语法(非常重要,必须学会)
非常之重要,必须学会
实际开发中我们用Promise封装用的比较多
两个回调函数:resolve 和 reject
步骤1(许下诺言)测试:
- 进行中
- 已完成
- 未完成
步骤2(获取诺言的结果)测试:- 诺言成功的结果
- 诺言失败的结果

状态凝固


4. promise 练习
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<button>好好挣钱</button>
<script>
// 需求
// 点击按钮,来判断年薪是否超过百万,如果超过,疯狂凡尔赛;如果没有的话,回去继承家业
document.querySelector('button').onclick = function() {
// 点击按钮的时候,许下诺言
let p = new Promise((resolve, reject) => {
console.log('我要好好挣钱,成家立业')
// 异步代码
// 时隔n年
setTimeout(() => {
// 随机一个数字,表示年薪(单位是万)
let money = parseInt(Math.random() * 200)
console.log(`现在我年薪${money}万`)
if(money >= 100) {
// 创业成功
resolve('发家致富')
} else {
// 创业失败
reject('搞钱太难了')
}
},1000)
})
// 获取结果
p.then((res) => {
// then 方法会在诺言成功的时候来执行
// 形参 res 对应的就是诺言成功的结果
console.log(res, '有手就行')
}).catch((err) => {
console.log(err, '还是回家继承家业吧')
})
}
</script>
</body>
</html>
效果:
5. Promise 的链式调用


6. Promise 解决回调地狱问题



7. 封装创建 promise 对象的过程

优化:


8. promise 的常用静态方法:.all 和 .race


axios.get() 后面可以跟 then 说明它是一个 promise 实例对象
axios请求方法(axios.get()等)的别名其实就是用promis封装的,也解释了之前使用 axios 它后面可以跟 then




四、案例 - 封装自己的 Ajax 函数


1阶段测试:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<button id="btnGet">发送get请求</button>
<button id="btnPost">发送post请求</button>
<script src="./lib/axios.js"></script>
<script>
// GET http://www.liulongbin.top:3009/api/get
// POST http://www.liulongbin.top:3009/api/post
// 提供myAxios来实现发送ajax请求 ajax 异步操作 ==> 需要使用promise封装ajax异步代码
function myAxios({method, url, params, data}) { // 解构赋值
// 记得将promise实例对象返回出去
return new Promise((resolve, reject) => {
// 在这写ajax异步代码
// ...
// console.log(method,url, params, data)
// 发送请求 + 处理响应
// 原生xhr
// 1. 创建出来xhr对象
// 2. 方式、url地址 ==> open()
// 3. send(请求体数据) 发送请求
// 1.
let xhr = new XMLHttpRequest()
// 2.
xhr.open(method, url)
// 3.
xhr.send()
// 处理响应
xhr.addEventListener('load',function(){
// console.log(xhr.response) // 服务器响应结果
// 把 promise 实例对象的状态改成成功fulfilled
// 对结果进行反序列化 将 JSON格式 转化为 js对象
resolve(JSON.parse(xhr.response)) // resolve() 让 then 拿到结果
})
// 监听 error 事件 处理请求失败 触发 catch 方法
xhr.addEventListener('error', function() {
// reject(JSON.parse(err))
reject('网络异常,请求失败,请稍后重试~')
})
})
}
// 发送get请求
document.querySelector('#btnGet').addEventListener('click',function(){
// 使用自己封装的Ajax函数来发送请求
myAxios({
method: 'get',
url: 'http://www.liulongbin.top:3009/api/get',
params: {
name: 'ts',
age: 22
}
}).then((res) => {
console.log(res) // 服务器响应结果
}).catch((err) => {
console.log(err)
})
})
// 发送post请求
document.querySelector('#btnPost').addEventListener('click',function(){
myAxios({
method: 'post',
url: 'http://www.liulongbin.top:3009/api/post',
params: {
name: 'ts',
age: 22
},
data: {
a: 1,
b: 2
}
}).then((res) => {
console.log(res) // 服务器响应结果
})
})
</script>
</body>
</html>
结果:
穿插一个知识点:把对象处理成字符串
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
let params = {
a: 1,
b: 2,
c: 3
}
// 需求:将params对象的键值对处理成 键值对的字符串 'a=1&b=2&c=3'
// 拆解
// 1. 对象 ==> 数组 ['a=1', 'b=2', 'c=3']
// 2. 把上面的数组变字符串 ['a=1', 'b=2', 'c=3'].join('&') 结果是 'a=1&b=2&c=3'
// 步骤
// 1. 先准备一个空数组 []
// 2. for...in 遍历对象 把对象中的键 和 值 添加到数组中(难度最大)
// 3. 数组使用 join
// 1.
let arr = []
// 2.
for(let key in params) {
console.log(key,params[key])
// console.log(key)
// console.log(params[key])
// 把键和值给push添加到arr数组中
arr.push(`${key} = ${params[key]}`)
}
console.log(arr)
console.log(arr.join('&'))
</script>
</body>
</html>
结果:







完整代码如下:最后还有优化过后的代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<button id="btnGet">发送get请求</button>
<button id="btnPost">发送post请求</button>
<script src="./lib/axios.js"></script>
<script>
// GET http://www.liulongbin.top:3009/api/get
// POST http://www.liulongbin.top:3009/api/post
// 提供myAxios来实现发送ajax请求 ajax 异步操作 ==> 需要使用promise封装ajax异步代码
function myAxios({method, url, params, data}) { // 解构赋值
// 记得将promise实例对象返回出去
return new Promise((resolve, reject) => {
// 在这写ajax异步代码
// ...
// console.log(method,url, params, data)
// 发送请求 + 处理响应
// 原生xhr
// 1. 创建出来xhr对象
// 2. 方式、url地址 ==> open()
// 3. send(请求体数据) 发送请求
// 1.
let xhr = new XMLHttpRequest()
// 在 open 之前,就对 params 查询参数做个处理
if(params) {
// if成立,表示params对象是存在的
// console.log('if成立,表示params对象是存在的')
let arr = []
// 2.
for(let k in params) {
// console.log(key,params[key])
// 把键和值给push添加到arr数组中
arr.push(`${k}=${params[k]}`)
}
// console.log(arr)
console.log(arr.join('&')) // name=ts&age=22
// 把键值对字符串拼接到url地址后面,并使用?隔开
url += `?${arr.join('&')}` // url = url + ?name=ts&age=22
}
// 2.
xhr.open(method, url)
// 3.
// xhr.send(请求体数据)
// 以下代码适用于get方式 ==> 没有请求体
// xhr.send()
// 需要判断,请求方式不为get的话,而且有data请求体数据的话,就来处理data数据
if(method === 'get'){
// 以下代码适用于get方式 ==> 没有请求体
// console.log('这是get请求方式')
xhr.send()
}else {
// post put ...方式
// 需要判断,请求方式不为get的话,而且有data请求体数据的话,就来处理data数据
if(data) {
// data存在时,处理data数据
// 记得还需要设置Content-Type
xhr.setRequestHeader('Content-Type', 'application/json')
// 把data对象处理成json字符串,发送给服务器
xhr.send(JSON.stringify(data))
}
}
// 处理响应
xhr.addEventListener('load',function(){
// console.log(xhr.response) // 服务器响应结果
// 把 promise 实例对象的状态改成成功fulfilled
// 对结果进行反序列化 将 JSON格式 转化为 js对象
resolve(JSON.parse(xhr.response)) // resolve() 让 then 拿到结果
})
// 监听 error 事件 处理请求失败 触发 catch 方法
xhr.addEventListener('error', function() {
// reject(JSON.parse(err))
reject('网络异常,请求失败,请稍后重试~')
})
})
}
// 发送get请求
document.querySelector('#btnGet').addEventListener('click',function(){
// 使用自己封装的Ajax函数来发送请求
myAxios({
method: 'get',
url: 'http://www.liulongbin.top:3009/api/get',
params: {
name: 'ts',
age: 22
}
}).then((res) => {
console.log(res) // 服务器响应结果
}).catch((err) => {
console.log(err)
})
})
// 发送post请求
document.querySelector('#btnPost').addEventListener('click',function(){
myAxios({
method: 'post',
url: 'http://www.liulongbin.top:3009/api/post',
params: {
name: 'ts',
age: 22
},
data: {
a: 1,
b: 2
}
}).then((res) => {
console.log(res) // 服务器响应结果
})
})
</script>
</body>
</html>
优化代码
优化1:
如图,当使用封装函数时输入的method是大小写混杂,判断语句是会出错的
解决方案:

优化2:
可以给代码添加这个功能
解决方案:
封装函数的时候给 method 设置为默认是get 请求
测试:

优化后的最终代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<button id="btnGet">发送get请求</button>
<button id="btnPost">发送post请求</button>
<script src="./lib/axios.js"></script>
<script>
// GET http://www.liulongbin.top:3009/api/get
// POST http://www.liulongbin.top:3009/api/post
// 提供myAxios来实现发送ajax请求 ajax 异步操作 ==> 需要使用promise封装ajax异步代码
function myAxios({method = 'get', url, params, data}) { // 解构赋值
// 记得将promise实例对象返回出去
return new Promise((resolve, reject) => {
// 在这写ajax异步代码
// ...
// console.log(method,url, params, data)
// 发送请求 + 处理响应
// 原生xhr
// 1. 创建出来xhr对象
// 2. 方式、url地址 ==> open()
// 3. send(请求体数据) 发送请求
// 1.
let xhr = new XMLHttpRequest()
// 在 open 之前,就对 params 查询参数做个处理
if(params) {
// if成立,表示params对象是存在的
// console.log('if成立,表示params对象是存在的')
let arr = []
// 2.
for(let k in params) {
// console.log(key,params[key])
// 把键和值给push添加到arr数组中
arr.push(`${k}=${params[k]}`)
}
// console.log(arr)
console.log(arr.join('&')) // name=ts&age=22
// 把键值对字符串拼接到url地址后面,并使用?隔开
url += `?${arr.join('&')}` // url = url + ?name=ts&age=22
}
// 2.
xhr.open(method, url)
// 3.
// xhr.send(请求体数据)
// 以下代码适用于get方式 ==> 没有请求体
// xhr.send()
// 需要判断,请求方式不为get的话,而且有data请求体数据的话,就来处理data数据
// toLowerCase() 字符串转小写,toUpperCase() 字符串转大写,转规范的小写字母可以保证if判断语句顺利进行
if(method.toLowerCase() === 'get'){
// 以下代码适用于get方式 ==> 没有请求体
// console.log('这是get请求方式')
xhr.send()
} else {
// post put ...方式
// 需要判断,请求方式不为get的话,而且有data请求体数据的话,就来处理data数据
if(data) {
// data存在时,处理data数据
// 记得还需要设置Content-Type
xhr.setRequestHeader('Content-Type', 'application/json')
// 把data对象处理成json字符串,发送给服务器
xhr.send(JSON.stringify(data))
}
}
// 处理响应
xhr.addEventListener('load',function(){
// console.log(xhr.response) // 服务器响应结果
// 把 promise 实例对象的状态改成成功fulfilled
// 对结果进行反序列化 将 JSON格式 转化为 js对象
resolve(JSON.parse(xhr.response)) // resolve() 让 then 拿到结果
})
// 监听 error 事件 处理请求失败 触发 catch 方法
xhr.addEventListener('error', function() {
// reject(JSON.parse(err))
reject('网络异常,请求失败,请稍后重试~')
})
})
}
// 发送get请求
document.querySelector('#btnGet').addEventListener('click',function(){
// 使用自己封装的Ajax函数来发送请求
myAxios({
// method: '',
url: 'http://www.liulongbin.top:3009/api/get',
params: {
name: 'ts',
age: 22
}
}).then((res) => {
console.log(res) // 服务器响应结果
}).catch((err) => {
console.log(err)
})
})
// 发送post请求
document.querySelector('#btnPost').addEventListener('click',function(){
myAxios({
method: 'post',
url: 'http://www.liulongbin.top:3009/api/post',
params: {
name: 'ts',
age: 22
},
data: {
a: 1,
b: 2
}
}).then((res) => {
console.log(res) // 服务器响应结果
})
})
</script>
</body>
</html>
五、案例 - 分类导航
在线接口文档
1. 封装代码
事先准备,首先将我们在上一个案例中封装的函数,放到一个新建的 js 文件中,以后想使用这个函数,引用 js 文件即可。
2. 目标效果展示

3. 获取一级导航
3.1 测试:





对 res 数组进行分析


3.2 实现渲染一级导航
- 实现渲染


- 优化代码,更换实际数据


4. 获取二级目录
4.1 测试


4.2 渲染二级目录


完整代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<link rel="stylesheet" href="./css/index.css" />
</head>
<body>
<div class="container">
<ul class="top">
<!-- <li>
<a href="javascript:;">首页</a>
<ul class="sub">
<li>
<a href="javascript:;">
<span>砂锅厨具</span>
<img src="https://yanxuan.nosdn.127.net/3102b963e7a3c74b9d2ae90e4380da65.png?quality=95&imageView" alt="">
</a>
</li>
<li>
<a href="javascript:;">
<span>砂锅厨具</span>
<img src="https://yanxuan.nosdn.127.net/3102b963e7a3c74b9d2ae90e4380da65.png?quality=95&imageView" alt="">
</a>
</li>
</ul>
</li> -->
</ul>
</div>
<!-- 导入自己封装的axios函数 -->
<script src="./myAxios.js"></script>
<!-- <script src="./lib/axios.js"></script> -->
<script>
// 在线接口文档: https://www.showdoc.com.cn/1834761734600444/8477922262544492
let box = document.querySelector('.top')
// 配置请求根路径
// axios.defaults.baseURL = 'http://ajax-api.itheima.net'
// myAxios() 使用自己封装的myAxios函数来发送请求 去获取一级 + 二级导航数据
// 得到的结果是一级导航
myAxios({
// method: 'get', 我们封装的函数里默认的method就是get
url: 'http://ajax-api.itheima.net/api/category/top'
}).then((res) => {
console.log(res)
// 继续发送请求,获取二级导航数据
// 遍历res.data数组
// map 可以遍历数组,还可以映射得到新数组
let arr = res.data.map(item => {
console.log(item.id) // 一级导航分类id
return myAxios({
url: 'http://ajax-api.itheima.net/api/category/sub',
params: {
id: item.id
}
})
})
console.log(arr)
// 如何去获取到所有的二级导航数据
// Promise.all(arr).then(() => {}) // 不要这样写
// return 新的promise对象
return Promise.all(arr)
}).then((res) => {
console.log(res) // 数组,数组里面是每一个promise对象成功的结果
box.innerHTML = res.map(item => {
// 先处理号二级目录
let subStr = item.data.children.map(sub => {
return `
<li>
<a href="javascript:;">
<span>${sub.name}</span>
<img src="${sub.picture}" alt="">
</a>
</li>
`
}).join('')
console.log(subStr);
// 一级导航 + 二级目录的结构
// 处理好二级目录后 把代表它的 subStr 放进一级导航中
return `
<li>
<a href="javascript:;">${item.data.name}</a>
<ul class="sub">
${subStr}
</ul>
</li>
`
}).join('')
// console.log(str)
})
</script>
</body>
</html>
版权声明:本文为JOUKELOVE原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。













