封装Ajax--解决地狱回调问题

一、回调函数封装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)
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

哈哈ha~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值