Javascript 中ajax请求的回调金字塔和Promise

在之前的博文中,我们了解了,Js是一门单线程语言,不过存在一些异步执行的方法,它们会放到callback queue 中,等主线程stack中任务执行完成,再去执行callback queue 。 但是如果需要callback queue中的任务返回的数据怎么办,比如下边的回调金字塔

什么是回调金字塔
  • 举例说明
    存在一个需求,比如需要拿到回调中数据,根据数据判断是否显示一个banner图,这就要求将banner图的显示放到ajax回调成功返回的函数中,这种写法就称为 “回调金字塔”

  • 比如下边代码

    	// 伪代码表示
    	ajax('xxx',function (){
    	  	createDom();
    	  	btn.onclick = function (){
    	      ajax('xxx',function(){
    	        // ....
    	         bc.onclick = function (){
    	           ajax('xxx',function(){
    	             //...
    	           })
    	         }
    	        
    	      })
    	    }
    	})
    

    代码中,在ajax返回成功之后,去创建dom并且绑定了一个点击事件。这样写法是没语法问题的,但是存在 代码结构复杂,不利于阅读的问题,为了解决这种问题,引入Promise

什么是 Promise

Promise是 Promises/A+规范 提供,后来被ES6 收录为标准

Promise 异步编程的一种解决方案,是一个构造函数 , 可以理解为用写同步代码的方式编写异步代码

  • Promise 语法
    基本写法

    new Promise(function(resolve,reject){...})
    

    参数 是一个函数 ,函数有两个参数

    • 参数1:resolve函数,调用后会把Promise的状态从pending变为resolved
    • 参数2:reject函数,调用后会把Promise的状态从pending变为rejected

    注意

    • 1、两个函数都可以传参,参数代表异步操作的结果
    • 2、两个函数调用后会执行then方法的两个参数(对应执行)
  • promise对象 : 对象如下图

    var p = new  Promise(function(resolve,reject){})
    console.dir(p) // 查看p对象的状态
    

    在这里插入图片描述
    截图可以看出 Promise是一个对象,也就是说与其他JavaScript对象的用法,没有什么两样;

    不过,它起到代理作用(proxy),充当异步操作与回调函数之间的中介。它使得异步操作具备同步操作的接口,使得程序具备正常的同步运行的流程,回调函数不必再一层层嵌套

    Promise对象存在状态。几个状态如下

    • pending 初始状态,既不是成功,也不是失败
    • fulfilled 操作成功
    • rejected 操作失败
  • 函数可以修改状态
    resolve和 reject会改变Promise对象的状态,比如下边代码执行之后,状态改为resolved

    //resolve 调用后会把Promise的状态从pending变为resolved
    //reject函数,调用后会把Promise的状态从pending变为rejected
    var p = new  Promise(function(resolve,reject){
      resolve();
    })
    console.dir(p) // 查看p对象的状态
    

    在这里插入图片描述

    注意 :

    • 状态只能改变一次,要么从初始变为成功,要么从初始变为失败。并且改变后就不会再变了
    • 如果状态为fulfilled或者rejected时又可以称为resolved状态(已定型)
  • resolve 和 reject 分别对应then中第一个、第二个函数

     const p=new Promise((resolve,reject)=>{
       //resolve('状态变为成功,会调用then里的第一个参数');
       reject('状态变为失败,会调用then里的第二个参数');
     }).then(
       value=>{
         console.log(value);		//状态变为成功,会调用then里的第一个参数
       },
       error=>{
         console.log(error);		//状态变为失败,会调用then里的第二个参数
       }
     );
    
    /** 
    const p=new Promise(function(resolve,reject){
       //resolve('状态变为成功,会调用then里的第一个参数');
       reject('状态变为失败,会调用then里的第二个参数');
     }).then(
       function(value){
         console.log(value);		//状态变为成功,会调用then里的第一个参数
       },
       function(error){
         console.log(error);		//状态变为失败,会调用then里的第二个参数
       }
     ); 
     **/
    

    上边代码定义了一个promise对象,它的then里边存在两个函数,至于走哪一个函数是根据Promise对象里边的函数(如下Js)决定的,如果promise中定义的函数最终执行的是resolve(第一个参数),就会走then中第一个函数,如果选择的是reject就会走then中第二个函数

    function(resolve,reject){
       //resolve('状态变为成功,会调用then里的第一个参数');
       reject('状态变为失败,会调用then里的第二个参数');
     }
    
then 方法可以被上边调用原因
  • promise中then方法原理
    之前提到了, 当我们选择resolve时,会去走then中第一个方法,选择reject会走then中第二个方法,那么为什么这样呢,或者说,Js是如何做到这一点的,其实这和Promise原型设计有关

    then方法时直接写在Promise的原型之中,源码如下

    Promise.prototype.then(onFulfilled,onRejected)
    
    • onFulfilled,当调用resolve的时候,该函数被执行(处理成功状态)
    • onRejected(可选),当调用reject的时候,该函数被执行(处理失败状态)
Promise.then方法链式调用
  • 什么是链式调用
    链式调用,就是可以在promise对象.then()之后,如果有需求可以继续调用then。因为then方法返回值就是promise对象,比如下边的代码
    console.dir(p.then()); // 输出依然是个Promise对象 
    console.log(p==p.then());	//false
    
  • 用处
    解决之前提到的调用金字塔问题,比如下边代码 (注意用伪码写的,post地址不存在)
    var p = new Promise(function(resolve, reject){
     	 $.post("demo_test.html",function(data,status){
        	if(data.age > 13){
        		resolve(13)
        	}
    	});
    });
    p.then(function(value){              
      console.log(value);
      return value*2;
    }).then(function(value){             
      console.log(value);
    })
    
    上边代码中,第一次调用then处理是对传参 * 2 ; 第二次调用时打印值。最终输出结果也证明了then可以实现链式调用, 实际上
Promise中catch函数
  • catch函数用法

    Promise.prototype.catch(onRejected) , 作用与then里的onRejected一样,都用于指定发生错误时的回调函数, 建议用catch方法代替then的第二个参数。这样能捕获前面then方法执行时候的错误

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值