基础知识
AJAX概念
AJAX概念:是浏览器与服务器进行数据通信的技术。
认识URL
定义:统一资源定位符,简称网址,用于访问网络上的资源。
组成:
- http协议:超文本传输协议,规定浏览器和服务器之间传输数据的格式。
- 域名:标记服务器在互联网中方位。
- 资源位置:标记资源在服务器下的具体位置。
查询参数
定义:浏览器提供给服务器的额外信息,让服务器返回浏览器想要的数据。
语法:http://xxxx.com/xxx/xxx?参数名1=值1&参数名2=值2
常用请求方式
请求方式:对服务器资源,要拽行动的操作
请求方法 | 操作 |
---|---|
GET | 获取数据 |
POST | 数据提交 |
PUT | 修改数据(全部) |
DELETE | 删除数据 |
PATCH | 修改数据(部分) |
报文
HTTP协议:规定了浏览器发送及服务器返回内容的格式。
请求报文
请求报文:浏览器按照HTTP协议要求的格式,发送给服务器的内容。
请求报文由以下几个部分组成:
- 请求行:包含请求方法、URL和协议。
- 请求头:以键值对格式携带的附加信息,例如
Content-Type
。 - 空行:用于分隔请求头,空行之后是发送给服务器的资源。
- 请求体:实际发送给服务器的资源。
调试窗口查看报文
在浏览器任意页面右键找到检查
或者直接F12
键打开调试窗口。
然后找到网络
,找到Fetch/XHR
。
然后就可以在调试窗口里面查看报文信息啦!
请求头在标头
中观看:
响应头就在响应标头
中查看:
请求标头保存请求头的信息:
可以点击
原始
显示原始的请求头信息
请求体在载荷
中观看:
响应体就在响应
中查看:
如果响应的内容比较多的时候,可以在
预览
窗口查看,就会以json数据的格式呈现出来。
响应报文
响应报文:服务器按照HTTP协议要求的格式,返回给浏览器的内容。
它由以下几个部分组成:
- 响应行(状态行):包含协议、HTTP响应状态码和状态信息。
- 响应头:以键值对格式携带的附加信息,例如
Content-Type
。 - 空行:用于分隔响应头,空行之后是服务器返回的资源。
- 响应体:实际返回给浏览器的资源。
HTTP响应状态码
HTTP响应状态码:用来表明请求是否成功完成
状态码 | 说明 |
---|---|
1xx | 信息 |
2xx | 成功 |
3xx | 重定向消息 |
4xx | 客户端错误 |
5xx | 服务端错误 |
接口文档
接口文档:由后端提供的描述接口
的文章
接口:使用AJAX和服务器通讯时,使用的URL
,请求方法
,以及参数
Axios
基本使用
使用方法:
-
引入axios:https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js
- 可以使用
console.log(axios)
检验是否拿到了axios对象
- 可以使用
-
使用axios函数
使用方法: 1. 传入配置对象。 2. 再用.then回调函数接收结果,并做后续处理。 axios({ url:‘目标资源地址’ }).then((返回结果)=>{ //在then回调函数中,第一个参数就是服务端返回的数据结果 //对服务器返回的数据做后续的处理 })
查询参数
语法:使用axios提供的params
选项
模版:
axios({
url:''
params:{
参数名:值
}
}).then(res =>{
//方法
})
⚠️注意:axios在运行时把参数名和值,会拼接到url?参数名=值
。
请求配置
语法:使用axios提供的 mothed
选项
模版:
method
:请求的方法(get可以省略不写)- data:提交数据
axios({
url:'',
params:{ 参数名:值 },
method:'请求方法',
data:{
参数名:值
}
}).then(res =>{
//方法
})
错误处理
语法:在then方法的后面,通过点语法调用catch
方法,传入回调函数并定义形参
。
模版:
axios({
//请求选项
}).then(res =>{
//处理数据
}).catch(err =>{
//错误处理
})
AJAX原理
XMLHttpRequest
定义:XMLHttpRequest(XHR)对象用于与服务器交互。axios内部采用XMLHttpRequest与服务器交互。
使用步骤:
-
创建一个XHR对象
const xhr = new XMLHttpRequet()
-
调用open方法,配置请求方法和请求url地址
xhr.open(请求方式,请求路径)
-
监听loadend事件,接受响应结果
xhr.addEventListener('loadend',() = >{ //console.log(xhr.response) //转化为json对象 console.log(JSON.parse(xhr.response)) })
-
send方法发起请求
xhr.send()
查询参数
直接在open
方法中拼接查询字符串:
xhr.open(get,请求路径?参数名=参数值&参数名2=参数值2&...)
URLSearchParams
将对象格式数据,转化为查询字符串
const obj = new URLSearchParams({
对象名1,对象名2...
})
const str = obj.toString()
const xhr = new XMLHttpRequet()
xhr.open(请求方式,请求路径?${str})
提交参数
const xhr = new XMLHttpRequet()
xhr.open(post,请求路径)
xhr.addEventListener('loadend',() = >{
//console.log(xhr.response)
//转化为json对象
console.log(JSON.parse(xhr.response))
})
//请求体参数步骤:
// 1. 设置请求头数据类型,根据接口文档设置application/json
xhr.setRequestHeader('Content-Type','applicatio/json')
// 2.在send方法中携带参数
const obj ={
username:'',
password:''
}
//3.转化成字符串
const data = JSON.stringfy(obj)
xhr.send(data)
封装简易axios(了解)
步骤:
-
定义一个函数,接受配置对象,返回Promise对象
function myAxios(option){ const { url,method } = option return new Promise((resolve,reject) => { }) }
-
发起XHR请求
function myAxios(option){ const { url,method } = option return new Promise((resolve,reject) => { const xhr = new XMLHttpRequest xhr.open(method,url) xhr.addEventListener('loadend', ()=>{}) xhr.send() }) }
-
调用成功或失败的处理程序
function myAxios(option){ const { url,method } = option return new Promise((resolve,reject) => { const xhr = new XMLHttpRequest xhr.open(method,url) xhr.addEventListener('loadend', ()=>{ resolver(xhr.response) }) xhr.send() }) }
-
使用封装的函数
myAxios({ url:'', method:'' }).then(res => { console.log(res) })
如果需要查询参数:
-
调用函数的时候传入
params
参数myAxios({ url:'', method:'', params:{ 参数1:值1... } }).then(res => { console.log(res) })
-
基于URLSearchParmas转化并携带url上
let { url,method,params } = option params = parmas ? new URLSearchParmas(params).toString():'' url = params ? url+'?' +params:url
如果需要请求参数
-
同样的先调用函数传入
data
参数 -
解构
data
let { url,method,params,data } = option
-
设置data
if(data){ //1. 设置请求头 xhr.setRequestHeader('Content-Type','application/json') //2. 处理数据 // data = JSON.stringify(data) //3. 发送请求 }else{ xhr.send(JSON.stringfy(data)) }
-
错误处理
if(xhr.status >= 200 && xhr.status < 300){ resolver(JSON.parse(xhr.response)) }else{ reject(new Error(xhr.response)) }
Promise
Promise对象用于表示一个异步操作的最终完成(或失败)及其结果值。
好处:
-
逻辑更清晰
-
了解axios函数内部运作机制
-
能解决回调函数地狱问题
语法:
-
创建Promise对象
const p = new Promise(function(成功,失败){ }) //一般写成以下👇形式
-
执行异步操作并传递结果
const p = new Promise(function (resolve,reject){ resolve('成功') })
- 成功调用:resolve(值)触发then
- 失败调用:reject(值)触发catch
-
接受结果
p.then(result => { //成功 }) p.catch(error => { //失败 })
Promise三种状态
作用:了解Promise对象如何关联的处理函数,以及代码执行顺序。
概念:一个Promise对象,必然处于以下几种状态之一
状态 | 含义 |
---|---|
待定(pending) | 初始状态,既没有被兑现,也没有被拒绝 |
已兑现(fulfilled) | 意味着,操作成功完成 |
已拒绝(rejected) | 意味着,操作失败 |
状态凝固:Promise的特性,一旦状态从pending修改为其他状态后就不会再次修改了。
Promise+XHR
-
创建Promise对象
-
在Promise对象中使用XHR
-
接受结果,使用Promise对象
const p = new Promise(function(resolve,reject){ const xhr = new XMLHttpRequest() xhr.open(请求方式,请求地址) xhr.addEventListener('loadend',() => { //成功 resolve(xhr.response) //失败 //reject(xhr.response) }) xhr.send() }) p.then(result => { //成功 }) p.catch(error => { //失败 })
同步与异步
同步代码:逐行执行,需原地等待结果后才继续向下执行。
异步代码:调用后耗时,不阻塞代码继续执行(不必原地等待),在将来完成后触发一个回调函数。(例子:定时器、Axios、事件)
小习题:
答案:
由此可知,异步代码是通过回调函数来接受结果
回调地狱问题
概念:回调函数嵌套回调函数就是回调地狱
缺点:可读性差,异常无法获取,耦合性严重,牵一发动全身。
链式调用
概念:依靠then()
方法会返回一个新生成的Promise对象特性,继续串联下一环任务,直到结束,then回调函数中的返回值会影响新生成的Promise对象最终状态和结果。
then回调函数中,return的值传给了新的Promise对象。
Promise链式调用的作用是解决了回调函数嵌套的问题。
const p = new Promise((resolver,reject) => {
resolve('成功1')
})
p.then(res => P{
console.log(res) //这里打印的是('成功1')
return new Promise((resolve,reject) =>{
resolve(res + '成功2')
})
}).then(res => {
console.log(res) //这里打印的是(res + '成功2')
})
async、await关键字
定义:async函数是使用async
关键字声明的函数。async函数是一个构造函数的实例,并且其中允许使用awai
关键字。async
和await
关键字让我们可以用一种更加简洁的方式写出基于Promise
的异步行为,而无需刻意地链式调用Promise
。
使用方法:在async函数内,使用await关键字取代then函数,等待获取Promise对象成功状态的结果值。
模版:
async function render(){
const res = await axios({
url:'',
method:''
})
}
//调用async
render()
注意:
- await必须用在async修饰的函数内
- await会组织“异步函数内”代码继续执行,原地等待结果
async函数错误处理
因为async函数只能获取成功状态
的结果值,如果发生错误了,这个时候就要使用到try...catch
方法来捕获错误。try...catch
语句标记要尝试的语句块,并指定一个出现异常时抛出的响应。
语法:
try{
//要执行的代码
} catch(error){
//error接受的是错误信息
}
那么我们直接跟上面的代码进行修改:
async function render(){
try{
const res = await axios({url:'',method:''})
} catch(err){
console.log(new Error(err)) //错误处理
}
}
//调用async
render()
事件循环
原因:JavaScript单线程(某一刻只能执行一行代码),为了让耗时代码不阻塞其他代码运行,设计了事件循环模型(EventLoop)。
定义:执行和收集异步任务的模型(机制),在调用栈空闲的时候,会反复调用任务列表里面回调函数的执行机制,叫做事件循环。
执行过程:
- 执行同步代码,遇到异步代码交给宿主环境执行
- 异步有了结果后,把回调函数放入任务队列排队
示例:
这段代码示例,展示了如何使用console.log
函数和setTimeout
函数来打印数字到控制台。不过,它并不是一个“时间循环”,而是展示了JavaScript中的异步执行和事件循环机制。
console.log(1);
立即执行,打印数字1到控制台。setTimeout(function() { console.log(2); }, 0);
设置了一个定时器,当定时器到期时,会将一个匿名函数加入到事件队列中。这个定时器设置的延迟是0毫秒,意味着它将在当前执行栈清空后的下一个事件循环迭代中执行。打印数字2。console.log(3);
立即执行,打印数字3到控制台。setTimeout(function() { console.log(4); }, 2000);
设置了另一个定时器,延迟2000毫秒后执行,打印数字4。console.log(5);
立即执行,打印数字5到控制台。
执行顺序如下:
- 首先打印1。
- 然后设置第一个定时器,但不会立即执行。
- 接着打印3。
- 然后打印5。
- 事件循环继续,第一个定时器到期后执行,打印2。
- 2000毫秒后,第二个定时器到期执行,打印4。
所以,最终的打印顺序是:1, 3, 5, 2, 4。
宏任务与微任务
ES6之后引入了Promise对象,让JS引擎也可以发起异步任务。
异步任务分为:
- 宏任务:由
浏览器
环境执行异步代码- js脚本执行事件
- 定时器
- AJAX请求完成事件
- 用户交互事件
- 微任务:由
JS引擎
环境执行的异步代码- Promise对象.then()方法(⚠️注意:Promise本身是同步的,而then和catch回调函数是异步的)
执行顺序:
- 执行第一个
script
脚本事件宏任务,里面同步代码。 - 遇到
宏任务/微任务
交给数组环境,由结果回调函数进入对应队列 - 当执行栈空闲的时候,
清空微任务
队列,在执行下一个宏任务,循环往复。
示例:
Promise.all方法
作用:合并多个Promise对象,等待所有完成(或某一个失败),做后续逻辑
语法:
const p = Promise.all([Promise对象,Promise对象,...])
p.then(resule =>{
//result结果
}).catch(error =>{
//第一个失败的Promise对象,抛出的异常
})