一、axios
是什么:AJAX是异步的JavaScript和XML。它可以在不重新刷新页面的情况下与服务器通信,交换数据,或更新页面。
概念:AJAX是浏览器与服务器进行数据通信的技术。
1、使用axios库与服务器进行数据通信
(1)引入axios.js
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
(2)使用axios函数
axios({ url: '目标资源地址' }).then(result => {}) <p class="my-p"></p> <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script> <script> axios({ url: 'http://hmajax.itheima.net/api/province' }).then(result => { console.log(result.data.list.join('<br>')) document.querySelector('.my-p').innerHTML = result.data.list.join('<br>') })
2、认识url
(1)http协议
超文本传输协议,规定浏览器和服务器之间传输数据的格式
(2)域名
服务器名
(3)资源路径
标记资源在服务器的具体位置
3、URL查询参数
(1)定义:浏览器提供给服务器的额外信息,让服务器返回浏览器想要的数据
(2)语法
http://xxx.com/xxx/xxx?参数名1=值1\&参数名2=值2
(3)使用axios提供的params选项获取数据
axios({ url:'目标资源地址' params:{ 参数名:值 } }).then(result=>{ })
4、常用的请求方法
使用axios提供的post方法和data选项获取数据
axios({ url:'目标资源地址' method:'post' data:{ 参数名:值 } }).then(result=>{ })
5、axios错误处理
- 场景:再次注册相同的账号,会遇到报错信息
- 步骤:
- (1)拿到报错信息: 利用.catch方法
- (2)获取错误信息:error.response.data.message
完整代码
axios({
url: 'https://hmajax.itheima.net/api/register',
method: 'post',
data: {
username: "tyy00916",
password: "123456"
}
}).then(() => {
console.log('注册成功')}).catch(error => { alert(error.response.data.message) })
6、请求报文
定义:浏览器发送给服务器的内容
组成:
查看请求报文:
7、响应报文
(1)是什么
服务器按照HTTP协议要求的格式,返回给浏览器的内容
(2)格式
(3)HTTP响应状态码
用来表明请求状态是否成功完成
404:url写错,一般是在服务器找不到资源
8、接口文档
用于描述接口的文章
接口:使用AJAX和服务器通讯时,使用的URL,请求方法,以及参数
9、form-serialize插件
- 作用:快速搜集表单元素的值
- 步骤:
(1)引入插件
<script src="./lib/form-seialize.js"></script>
(2)利用serialize方法搜集表单值
参数1:要获取哪个表单的数据
- 表单元素设置name属性,值会作为对象的属性名
- 建议name属性的值,最好和接口文档参数名一致
参数2:配置对象
- hash:
- true 数据结构为JS对象(推荐)
- false 数据结构为字符串
- empty:
true 获取空值(推荐)数据结构和标签结构一致
false 不获取空值
document.querySelector('.btn').addEventListener('click',()=>{
const form =ducument.querySelector('.example-form')
const data= serialize(form,{hash:true,empty:false})
}) //data为获取的表单对象合集10、图书管理案例:bootstrap弹框
功能:不离开当前页面,显示单独的内容,供用户操作
(1)用css控制弹框的显示与隐藏
(2)用JS控制弹框的显示与隐藏
- 步骤1:创建弹框对象
- 步骤2:调用弹框对象内置方法
- show() 显示
- hide() 隐藏
11、图片上传案例
<input type="file" class="upload"> <script> document.querySelector('.upload').addEventListener('change',e=>{ //1、获取图片文件 console.log(e.target.files[0]) //2、使用FormData携带图片文件 const fd= new FormData() fd.append('img',e.target.files[0]) //3、提交到服务器,获取图片url网址使用 axios({ url:'', method:'POST', data:fd }).then(result =>{ //取出图片url网址,用img标签加载显示 const imgUrl = result.data.data.url document.querySelector('.my-img').src=imgUrl }) }) </script>
二、AJAX原理:XMLHttpRequest
1、XMLHttpRequest 定义
XMLHttpRequest (XHR)对象用于与服务器交互。通过XHR可以在不刷新网页的情况下请求特定URL,获取数据。
2、XMLHttpRequest 查询参数
浏览器提供给服务器的额外信息,让服务器返回浏览器想要的数据
(1)案例:请求省份数据
/** * 目标: 根据省份和城市名字, 查询对应的地区列表 */ // 1. 查询按钮-点击事件 document.querySelector('.sel-btn').addEventListener('click', () => { // 2. 收集省份和城市名字 const pname = document.querySelector('.province').value const cname = document.querySelector('.city').value // 3. 组织查询参数字符串 const qObj = { pname, cname } // 查询参数对象 -> 查询参数字符串 const paramsObj = new URLSearchParams(qObj) const queryString = paramsObj.toString() console.log(queryString) // 4. 使用XHR对象,查询地区列表 const xhr = new XMLHttpRequest() xhr.open('GET', `http://hmajax.itheima.net/api/area?${queryString}`) xhr.addEventListener('loadend', () => { console.log(xhr.response) const data = JSON.parse(xhr.response) console.log(data) const htmlStr = data.list.map(areaName => { return `<li class="list-group-item">${areaName}</li>` }).join('') console.log(htmlStr) document.querySelector('.list-group').innerHTML = htmlStr }) xhr.send() })
(2)案例:提交数据
<button class="reg-btn">注册用户</button> <script> /** * 目标:使用xhr进行数据提交-完成注册功能 */ document.querySelector('.reg-btn').addEventListener('click', () => { const xhr = new XMLHttpRequest() xhr.open('POST', 'http://hmajax.itheima.net/api/register') xhr.addEventListener('loadend', () => { console.log(xhr.response) }) // 设置请求头-告诉服务器内容类型(JSON字符串) xhr.setRequestHeader('Content-Type', 'application/json') // 准备提交的数据 const userObj = { username: 'itheima007', password: '7654321' } const userStr = JSON.stringify(userObj) // 设置请求体,发起请求 xhr.send(userStr) }) </script>
三、Promise
1、定义
用于表示异步操作的最终完成(或失败)及其结果值
2、好处
逻辑更清晰、了解axios函数内部运作机制、能解决回调函数地狱问题
3、用法
4、Promise+XHR,获取省份列表表示
<p class="my-p"></p> <script> /** * 目标:使用Promise管理XHR请求省份列表 * 1. 创建Promise对象 * 2. 执行XHR异步代码,获取省份列表 * 3. 关联成功或失败函数,做后续处理 */ // 1. 创建Promise对象 const p = new Promise((resolve, reject) => { // 2. 执行XHR异步代码,获取省份列表 const xhr = new XMLHttpRequest() xhr.open('GET', 'http://hmajax.itheima.net/api/province') xhr.addEventListener('loadend', () => { // xhr如何判断响应成功还是失败的? // 2xx开头的都是成功响应状态码 if (xhr.status >= 200 && xhr.status < 300) { resolve(JSON.parse(xhr.response)) } else { reject(new Error(xhr.response)) } }) xhr.send() }) // 3. 关联成功或失败函数,做后续处理 p.then(result => { console.log(result) document.querySelector('.my-p').innerHTML = result.list.join('<br>') }).catch(error => { // 错误对象要用console.dir详细打印 console.dir(error) // 服务器返回错误提示消息,插入到p标签显示 document.querySelector('.my-p').innerHTML = error.message }) </script>
5、Promise+XHR+myaxios,获取省份列表表示
<p class="my-p"></p> <script> /** * 目标:封装_简易axios函数_获取省份列表 * 1. 定义myAxios函数,接收配置对象,返回Promise对象 * 2. 发起XHR请求,默认请求方法为GET * 3. 调用成功/失败的处理程序 * 4. 使用myAxios函数,获取省份列表展示 */ // 1. 定义myAxios函数,接收配置对象,返回Promise对象 function myAxios(config) { return new Promise((resolve, reject) => { // 2. 发起XHR请求,默认请求方法为GET const xhr = new XMLHttpRequest() xhr.open(config.method || 'GET', config.url) xhr.addEventListener('loadend', () => { // 3. 调用成功/失败的处理程序 if (xhr.status >= 200 && xhr.status < 300) { resolve(JSON.parse(xhr.response)) } else { reject(new Error(xhr.response)) } }) xhr.send() }) } // 4. 使用myAxios函数,获取省份列表展示 myAxios({ url: 'http://hmajax.itheima.net/api/province' }).then(result => { console.log(result) document.querySelector('.my-p').innerHTML = result.list.join('<br>') }).catch(error => { console.log(error) document.querySelector('.my-p').innerHTML = error.message }) </script>
6、Promise+XHR+myaxios,获取地区列表表示
<p class="my-p"></p> <script> /** * 目标:封装_简易axios函数_获取地区列表 * 1. 判断有params选项,携带查询参数 * 2. 使用URLSearchParams转换,并携带到url上 * 3. 使用myAxios函数,获取地区列表 */ function myAxios(config) { return new Promise((resolve, reject) => { const xhr = new XMLHttpRequest() // 1. 判断有params选项,携带查询参数 if (config.params) { // 2. 使用URLSearchParams转换,并携带到url上 const paramsObj = new URLSearchParams(config.params) const queryString = paramsObj.toString() // 把查询参数字符串,拼接在url?后面 config.url += `?${queryString}` } xhr.open(config.method || 'GET', config.url) xhr.addEventListener('loadend', () => { if (xhr.status >= 200 && xhr.status < 300) { resolve(JSON.parse(xhr.response)) } else { reject(new Error(xhr.response)) } }) xhr.send() }) } // 3. 使用myAxios函数,获取地区列表 myAxios({ url: 'http://hmajax.itheima.net/api/area', params: { pname: '辽宁省', cname: '大连市' } }).then(result => { console.log(result) document.querySelector('.my-p').innerHTML = result.list.join('<br>') }) </script>
7、Promise+XHR+myaxios,注册账号
<button class="reg-btn">注册用户</button> <script> /** * 目标:封装_简易axios函数_注册用户 * 1. 判断有data选项,携带请求体 * 2. 转换数据类型,在send中发送 * 3. 使用myAxios函数,完成注册用户 */ function myAxios(config) { return new Promise((resolve, reject) => { const xhr = new XMLHttpRequest() if (config.params) { const paramsObj = new URLSearchParams(config.params) const queryString = paramsObj.toString() config.url += `?${queryString}` } xhr.open(config.method || 'GET', config.url) xhr.addEventListener('loadend', () => { if (xhr.status >= 200 && xhr.status < 300) { resolve(JSON.parse(xhr.response)) } else { reject(new Error(xhr.response)) } }) // 1. 判断有data选项,携带请求体 if (config.data) { // 2. 转换数据类型,在send中发送 const jsonStr = JSON.stringify(config.data) xhr.setRequestHeader('Content-Type', 'application/json') xhr.send(jsonStr) } else { // 如果没有请求体数据,正常的发起请求 xhr.send() } }) } document.querySelector('.reg-btn').addEventListener('click', () => { // 3. 使用myAxios函数,完成注册用户 myAxios({ url: 'http://hmajax.itheima.net/api/register', method: 'POST', data: { username: 'itheima999', password: '666666' } }).then(result => { console.log(result) }).catch(error => { console.dir(error) }) }) </script>
四、同步代码和异步代码
1、作用
- 同步代码:逐行执行,需原地等待结果后,才继续向下执行
- 异步代码:调用时耗时,不阻塞代码继续运行(不必原地等待),在将来完成后触发一个回调函数
- JS有哪些异步代码
- setTimeout / setInterval
- 事件
- AJAX
2、回调函数地狱
- 是什么:在回调函数中嵌套回调函数,一直嵌套下去就形成了回调函数地狱
- 问题:可读性差,内部嵌套回调函数异常在外面.catch无法捕获
3、Promise-链式调用
案例:利用Promise链式调用解决回调函数地狱
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script> <script> /** * 目标:把回调函数嵌套代码,改成Promise链式调用结构 * 需求:获取默认第一个省,第一个市,第一个地区并展示在下拉菜单中 */ let pname = '' // 1. 得到-获取省份Promise对象 axios({url: 'http://hmajax.itheima.net/api/province'}).then(result => { pname = result.data.list[0] document.querySelector('.province').innerHTML = pname // 2. 得到-获取城市Promise对象 return axios({url: 'http://hmajax.itheima.net/api/city', params: { pname }}) }).then(result => { const cname = result.data.list[0] document.querySelector('.city').innerHTML = cname // 3. 得到-获取地区Promise对象 return axios({url: 'http://hmajax.itheima.net/api/area', params: { pname, cname }}) }).then(result => { console.log(result) const areaName = result.data.list[0] document.querySelector('.area').innerHTML = areaName }) </script>
五、async函数和await
1、定义
async和await关键字可以更简洁写出Promise的异步行为,无需刻意调用promise。
2、概念
在async函数内,使用await关键字取代then函数,等待获取Promise对象成功状态的结果值。
3、步骤
(1)定义一个async修饰函数
(2)await等待Promise对象成功的结果
案例代码
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script> <script> /** * 目标:掌握async和await语法,解决回调函数地狱 * 概念:在async函数内,使用await关键字,获取Promise对象"成功状态"结果值 * 注意:await必须用在async修饰的函数内(await会阻止"异步函数内"代码继续执行,原地等待结果) */ // 1. 定义async修饰函数 async function getData() { // 2. await等待Promise对象成功的结果 const pObj = await axios({url: 'http://hmajax.itheima.net/api/province'}) const pname = pObj.data.list[0] const cObj = await axios({url: 'http://hmajax.itheima.net/api/city', params: { pname }}) const cname = cObj.data.list[0] const aObj = await axios({url: 'http://hmajax.itheima.net/api/area', params: { pname, cname }}) const areaName = aObj.data.list[0] document.querySelector('.province').innerHTML = pname document.querySelector('.city').innerHTML = cname document.querySelector('.area').innerHTML = areaName } getData() </script>
4、async函数和await捕获错误
(1)语法
(2)案例代码
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script> <script> /** * 目标:async和await_错误捕获 */ async function getData() { // 1. try包裹可能产生错误的代码 try { const pObj = await axios({ url: 'http://hmajax.itheima.net/api/province' }) const pname = pObj.data.list[0] const cObj = await axios({ url: 'http://hmajax.itheima.net/api/city', params: { pname } }) const cname = cObj.data.list[0] const aObj = await axios({ url: 'http://hmajax.itheima.net/api/area', params: { pname, cname } }) const areaName = aObj.data.list[0] document.querySelector('.province').innerHTML = pname document.querySelector('.city').innerHTML = cname document.querySelector('.area').innerHTML = areaName } catch (error) { // 2. 接着调用catch块,接收错误信息 // 如果try里某行代码报错后,try中剩余的代码不会执行了 console.dir(error) } } getData() </script>
六、事件循环
1、执行过程
同步代码→调用栈
异步代码→宿主环境(浏览器)→任务队列
2、定义
执行代码和搜集异步任务的模型。在调用栈空闲,反复调用任务队列里回调函数的执行机制,就叫事件循环。
3、总结
4、宏任务和微任务
(1)宏任务
- 由浏览器执行的异步代码
(2)微任务
- 由JS引擎环境执行的异步代码
(3)JS代码如何执行
- 宏任务中的同步代码
- 遇到宏任务/微任务先交给宿主汉奸,有结果回调函数进入对应队列。然后先调用微任务队列,再调用宏任务队列
七、Promise.all静态方法
1、概念
合并多个Promise对象,等待所有 同时成功完成(或某一个失败),做后续逻辑
2、 语法
3、案例:请求天气
<ul class="my-ul"></ul> <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script> <script> /** * 目标:掌握Promise的all方法作用,和使用场景 * 业务:当我需要同一时间显示多个请求的结果时,就要把多请求合并 * 例如:默认显示"北京", "上海", "广州", "深圳"的天气在首页查看 * code: * 北京-110100 * 上海-310100 * 广州-440100 * 深圳-440300 */ // 1. 请求城市天气,得到Promise对象 const bjPromise = axios({ url: 'http://hmajax.itheima.net/api/weather', params: { city: '110100' } }) const shPromise = axios({ url: 'http://hmajax.itheima.net/api/weather', params: { city: '310100' } }) const gzPromise = axios({ url: 'http://hmajax.itheima.net/api/weather', params: { city: '440100' } }) const szPromise = axios({ url: 'http://hmajax.itheima.net/api/weather', params: { city: '440300' } }) // 2. 使用Promise.all,合并多个Promise对象 const p = Promise.all([bjPromise, shPromise, gzPromise, szPromise]) p.then(result => { // 注意:结果数组顺序和合并时顺序是一致 console.log(result) const htmlStr = result.map(item => { return `<li>${item.data.data.area} --- ${item.data.data.weather}</li>` }).join('') document.querySelector('.my-ul').innerHTML = htmlStr }).catch(error => { console.dir(error) }) </script>