一、回调函数封装Ajax
(一)普通Ajax请求数据
后端index.js注册网址并写入数据
var router=require("./router.js")
router.get("/news",function(req,res){
var obj={data:[{title:"新闻1",content:"内容1",id:1},
{title:"新闻2",content:"内容2",id:2},
{title:"新闻3",content:"内容3",id:3}
]}
var str=JSON.stringify(obj)
res.setHeader("content-Type","text/json;charset=utf8")
res.end(str)
})
router.get("/author",function(req,res){
var obj=[{name:"lily",id:1},
{name:"lucy",id:2},
{name:"jack",id:3}
]
var str=JSON.stringify(obj)
res.setHeader("content-Type","text/json;charset=utf8")
res.end(str)
})
前端index.html文件请求news的数据:
<button onclick="fn()">Ajax请求数据</button>
<script>
function fn(){
var xhr=new XMLHttpRequest()||new ActiveXObject("Microsoft.XMLHTTP")
xhr.open("GET","/news",true) //请求news的数据
xhr.send()
xhr.onreadystatechange=function(){
if(xhr.readyState==4&&xhr.status==200){
console.log(xhr.responseText)
//根据业务需求处理数据
}
}
}
</script>
前端index.html文件请求author的数据:
<button onclick="fn()">Ajax请求数据</button>
<script>
function fn(){
var xhr=new XMLHttpRequest()||new ActiveXObject("Microsoft.XMLHTTP")
xhr.open("GET","/author",true) //请求author的数据
xhr.send()
xhr.onreadystatechange=function(){
if(xhr.readyState==4&&xhr.status==200){
console.log(xhr.responseText)
//根据业务需求处理数据
}
}
}
</script>
请求 news 和 author 这两个网址接口的数据就要发送两次Ajax网络请求才能获得不同的数据,若想请求其他接口的数据就要写更多的网络请求代码。这样就很麻烦,因为每次请求的代码是一样的,只是请求的网址和请求到的数据的处理方式不同。所以,可以根据这个特点设计一个网络请求工具来简化代码,使网络请求更灵活。
(二)网络请求工具请求数据
tool(url,cb):
tool函数就是一个简单的封装了ajax网络请求的工具
tool函数先用ajax请求传入的第一个参数url对应网址
当请求到并返回数据时 就把数据传给cb函数使用(调用cb)去执行业务
此时能满足不同的网址请求和各样的业务,实现代码复用
示例:
当fn点击事件发生后,tool工具函数就会请求网址得到数据,再将数据传给业务(回调)函数,开始执行业务
前端index.html文件请求数据:(author.html同理)
<script src="./tool.js"></script> <!--引入工具文件 实现代码复用-->
<button onclick="fn()">工具函数请求数据</button>
<script>
function fn(){
tool("/news",function(str){
//将网络请求到的数据用于业务中(写页面)
var obj = JSON.parse(str)
for (let i = 0; i < obj.data.length; i++) {
console.log(obj.data[i],1111)
let box = document.createElement("div")
box.className = "box"
box.innerHTML = `<b>${obj.data[i].title}---${obj.data[i].content}</b>`
document.body.appendChild(box)
}
})
}
</script>
工具文件 tool.js
function tool(url, cb) {
//封装Ajax网络请求代码
var xhr = new XMLHttpRequest() || new ActiveXObject("Microsoft.XMLHTTP")
xhr.open("GET", url, true)
xhr.send()
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200) {
//将请求到的数据传给cb回调函数执行业务
cb(xhr.responseText)
}
}
}
后端index.js注册网址并写入数据
var router=require("./router.js")
router.get("/news",function(req,res){
var obj={data:[{title:"新闻1",content:"内容1",id:1},
{title:"新闻2",content:"内容2",id:2},
{title:"新闻3",content:"内容3",id:3}
]}
var str=JSON.stringify(obj)
res.setHeader("content-Type","text/json;charset=utf8")
res.end(str)
})
router.get("/author",function(req,res){
var obj=[{name:"lily",id:1},
{name:"lucy",id:2},
{name:"jack",id:3}
]
var str=JSON.stringify(obj)
res.setHeader("content-Type","text/json;charset=utf8")
res.end(str)
})
请求结果:
二、jquery封装Ajax
用回调函数封装Ajax需要自己设计tool函数,而通过jquery只需要一个引入一个jquery框架就可以实现以上效果
准备工作:引入jquery标签
修改以上代码:
1、弃用tool.js
2、将 <script src="./tool.js"></script> 替换为
<script src="https://lf9-cdn-tos.bytecdntp.com/cdn/expire-1-M/jquery/2.2.4/jquery.js" type="application/javascript"></script>
3、将tool函数名 替换为 $.get
示例:
前端author.html文件请求数据:(index.html同理)
<script src="https://lf9-cdn-tos.bytecdntp.com/cdn/expire-1-M/jquery/2.2.4/jquery.js"></script>
<button onclick="fn()">用jQuery请求数据</button>
<script>
function fn() {
$.get("/author", function(res) {
console.log(res)
})
}
</script>
请求结果:
三、promise封装Ajax
(一)回调地狱
- 回调地狱指的是异步任务中回调函数的层层嵌套
- 随着嵌套的层数增加,代码的可读性和维护性变差
- 常见的回调函数如在ajax请求回调、setTimeout、事件回调等中,以函数作为参数进行调用
示例:
ajax请求回调地狱
<h1>promise封装ajax</h1>
<script>
function fn() {
$.get("/ajax1", (res1) => {
console.log(res1, JSON.parse(res1), 1)
$.get("/ajax2", (res2) => {
console.log(res2, JSON.parse(res2), 2)
$.get("/ajax3", (res3) => {
console.log(res3, JSON.parse(res3), 3)
$.get("/ajax4", (res4) => {
console.log(res4, JSON.parse(res4), 4)
})
})
})
})
}
</script>
(二)promise
promise语法:
(1) promise:
Promise是一个 构造函数, 用于创建Promise对象
Promise对象:可以理解为一个处理异步操作的容器
(2) promise对象的三个状态.:
- pending(进行中)
- fulfilled (已成功)
- rejected(已失败)
- 只有异步操作的结果可以决定当前是哪一种状态 任何其他操作都无法改变这个状态
(3) promise对象的状态改变:
- 从pending变为fulfilled 此时应该执行 resolve()
- 从pending变为rejected 此时应该执行 reject()
- 一旦状态改变,就不会再变,任何时候都可以得到这个结果
- resolve() 和 reject() 只能执行一个
注:promise本质不是控制 异步代码的执行顺序,而是控制异步代码结果处理的顺序
(4) 使用:
1.实例化Promise对象 : 将异步操作放入Promise中
- resolve:异步操作 成功状态
- reject : 异步操作 失败状态
2.调用then() 方法: 处理异步操作结果
promise对象.then((data)=>{ 处理成功数据 },(err)=>{ 处理失败信息 })
promise静态方法:(常见于笔试题中)
- Promise.resolve():将现有对象转为 Promise 对象
var p1=Promise.resolve(200)//传入的数据 封装成产生正确数据的Promise对象 console.log(p1) //200 p1.then((data)=>console.log(data)) //等同于 var p1=new Promise((resolve,reject)=>{ resolve(200) }) p1.then((data)=>console.log(data))
- Promise.reject():返回一个新的 Promise 实例 该实例的状态为
rejected
var p3=Promise.reject(200) //传入的数据 封装成产生错误数据的Promise对象 console.log(p3) //200 p3.catch(e=>console.log(e)) //200
- Promise.all():用于将多个 Promise 实例,包装成一个新的 Promise 实例
var p1=new Promise((n1,n2)=>{ $.get("/ajax1",(data)=>{ n1(data) }) }) var p2=new Promise((n1,n2)=>{ $.get("/ajax2",(data)=>{ n1(data) }) }) var p3=new Promise((n1,n2)=>{ $.get("/ajax3",(data)=>{ n1(data) }) }) var p=Promise.all([p1,p2,p3]) p.then((arr)=>{ conosle.log(arr) }) /*只有当三个promise对象的状态都为fulfilled,p的状态才会变为fulfilled 此时p1,p2,p3的返回值组成一个数组,传递给p的回调函数 */ /*只要有一个promise对象被rejected,p的状态就会变成rejected 此时第一个被rejected的实例的返回值会传递给p的回调函数 */
(三)Promise解决回调地狱问题
原理 :
在then方法中返回一个promise对象
- 链式嵌套,需在上一个promise对象的then方法中返回下一个promise对象进而实现连调
示例:
解决上述异步回调地狱(回调函数层次嵌套)的问题
function myaxios(url) {
return new Promise((resolve, reject) => {
//封装ajax
try {
//try里的代码3种情况: 语法错误|语法正确但产生错误的业务数据|正确的业务数据
let xhr = new XMLHttpRequest() || ActiveXObject("xxx")
xhr.open("GET", url, true)
xhr.send()
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
console.log(123)
if (xhr.status == 200) {
resolve(xhr.responseText)
} else if (xhr.status == 404) {
reject(xhr.responseText)
} else {
reject("net err")
}
}
}
} catch (e) {
reject(xhr.responseText)
}
})
}
var p1 = myaxios('/ajax')
p1.then((data1) => {
console.log(data1)
return myaxios('/ajax1')
})
.then((data2) => {
console.log(data2)
return myaxios('/ajax2')
})
.then((data3) => {
console.log(data3)
return myaxios('/ajax3')
})
.then((data4) => {
console.log(data4)
})
.catch((e) => {
console.log(e)
})
四、axios网络请求工具
- 底层是用promise封装ajax封装出来的axios工具 实际是js文件库
1.引入:同jquery
<script src="https://lf3-cdn-tos.bytecdntp.com/cdn/expire-1-M/axios/0.26.0/axios.js"></script>
2.对以上代码进行优化
var p1=axios('/ajax')
p1.then((data1)=>{
console.log(data1.data)
return axios('/ajax1')
})
.then((data2)=>{
console.log(data2.data)
return axios('/ajax2')
})
.then((data3)=>{
console.log(data3.data)
return axios('/ajax3')
})
.then((data4)=>{
console.log(data4.data)
})
.catch((e)=>{
console.log(e)
})
五、fetch
- 是浏览器自带的api 是原生js 不必引入第三方框架 直接使用(前端)
- 用于发起获取资源的请求
- 它返回一个 promise,这个 promise 会在请求响应后被 resolve,并传回 Response 对象
- 采用promise方式但不是promise
- 底层网络请求不同于ajax和jsonp
- 虽然功能很好 但不适用于业务
示例:
// 直接请求ajax1
var res=fetch("/ajax1")
//res是一个promise对象 这个对象内部有后端传过来的二进制包
res.then((data)=>{
return data.json() //调用函数解二进制包
})
.then((result)=>{
console.log(result)
})
六、fetch ajax和axios 的区别
写得很详细的一个博主的文章:
原文链接:https://blog.csdn.net/qq_43539854/article/details/125053587
七、async 高级函数
- async函数是ES7中引入的更为高级的异步处理机制, 相当于promise语法的 “高级写法”
- async和await异步函数 : 这两个关键字只能用于函数,一定要放在async修饰的函数里面用
- async关键字: 修饰函数 表示这个函数内部有异步操作
- await关键字: 等待异步执行完毕
- 代码按顺序执行 可维护性好
async语法
(1)函数前面使用async修饰
(2)函数内部:promise操作使用await修饰 await代替then方法取数据
- await 后面是promise对象, 左侧的返回值就是这个promise对象的then方法中的结果
- await 只能取出正确的数据
- await 必须要写在async修饰的函数中,不能单独使用,否则程序会报错
- await 是遍历器的语法糖
示例:
终极高内聚低耦合
let data1=await new Promise((n1,n2)=>{n1(2000)})
console.log(data1) //打印2000
let data2=await axios('/ajax2')
console.log(data2)
let data3=await axios('/ajax3')
console.log(data3)
let data4=await axios('/ajax4')
console.log(data4)