zoukankan      html  css  js  c++  java
  • ES6的Promise对象

      //------请求A 开始---------
        $.ajax({
            success:function(res1){
    
    
                //------请求B 开始----
                $.ajax({
                    success:function(res2){
    
    
                        //----请求C 开始---
                        $.ajax({
                            success:function(res3){
                            }
                        });
                        //---请求C 结束---
    
    
                    }    
                });
                //------请求B 结束-----
    
    
            }
        });
        //------请求A 结束---------
    
     
    
            上面的案例,假设请求C需要依赖请求B返回的数据,所以,C只能放在B的success函数内;B需要依赖A请求得到的数据作为参数,所以,B只能放在A的success函数内;也就是:请求A包含着请求B,请求B又包含了请求C。
    
    
    
            就这样,请求顺序为:请求A -> 请求B -> 请求C,最后你也能顺利的完成了任务。
    
    
    传统写法的不足
            
    
            但是这样写,会有一些缺点:
    
    
    
    1.  如果存在多个请求操作层层依赖的话,那么以上的嵌套就有可能不止三层那么少了,加上每一层还会有复杂的业务逻辑处理,代码可读性也越来越差,不直观,调试起来也不方便。如果多人开发的时候没有足够的沟通协商,大家的代码风格不一致的话,更是雪上加霜,给后面的维护带来极大的不便。
    
    
    
    
    2.  如果请求C的需要依赖A和B的结果,但是请求A和B缺互相独立,没有依赖关系,以上的实现方式,就使得B必须得到A请求完成后才可以执行,无疑是消耗了更多的等待时间。
    
    
    
    
    
            既然使用这种回调函数层层嵌套(又称:回调地狱)的形式存在缺点,ES6想了办法治它,所以就有了Promise的出现了。
    
    
    
            那么我们就知道了:Promise对象能使我们更合理、更规范地进行处理异步操作。
    
    
    
    
    Promise的基本用法 
            
    
            接下来,我们就看看它的基本用法:
    
    
    
    
        let pro = new Promise(function(resolve,reject){
            //....
        });
        
    
    
            Promise对象是全局对象,你也可以理解为一个类,创建Promise实例的时候,要有那个new关键字。参数是一个匿名函数,其中有两个参数:resolve和reject,两个函数均为方法。resolve方法用于处理异步操作成功后业务;reject方法用于操作异步操作失败后的业务。
    
    
    
    
    Promise的是三种状态
            
    
    Promise对象有三种状态:
    
    pending:刚刚创建一个Promise实例的时候,表示初始状态;
    
    fulfilled:resolve方法调用的时候,表示操作成功;
    
    rejected:reject方法调用的时候,表示操作失败;
    
    
    
    
            状态只能从 初始化 -> 成功  或者  初始化 -> 失败,不能逆向转换,也不能在成功fulfilled 和失败rejected之间转换。
    
    
    
    
        let pro = new Promise(function(resolve,reject){
            //实例化后状态:pending
    
            if('操作成功'){
                resolve();
                //resolve方法调用,状态为:fulfilled
            }else{
                reject();
                //reject方法调用,状态为:rejected
            }
        });
        
    
    
            上面的注释,讲清楚了一个Promise实例的状态改变情况。
    
    
    
            初始化实例后,对象的状态就变成了pending;当resolve方法被调用的时候,状态就变成了:成功fulfilled;当reject方法被调用的时候,状态就会有pending变成失败rejected。
    
     
    
    
    then( )方法
    
    
            了解了Promise的创建和状态,我们来学习一个最重要的实例方法:then( )方法。
    
    
    
            then( )方法:用于绑定处理操作后的处理程序。
    
    
    
        
        pro.then(function (res) {
            //操作成功的处理程序
        },function (error) {
            //操作失败的处理程序
        });
        
    
    
            参数是两个函数,第一个用于处理操作成功后的业务,第二个用于处理操作异常后的业务。
    
    
    
    
    catch( )方法 
            
    
            对于操作异常的程序,Promise专门提供了一个实例方法来处理:catch( )方法。
    
    
    
    
        pro.catch(function (error) {
            //操作失败的处理程序
        });
        
            
    
            catch只接受一个参数,用于处理操作异常后的业务。
    
    
    
            综合上面的两个方法,大家都建议将then方法用于处理操作成功,catch方法用于处理操作异常,也就是:
    
    
    
    
        pro.then(function (res) {
            //操作成功的处理程序
        }).catch(function (error) {
            //操作失败的处理程序
        });
        
    
    
            之所以能够使用链式调用,是因为then方法和catch方法调用后,都会返回promise对象。
    
     
    
            讲了那么多,如果你之前一点都没接触过Promise的话,现在一定很懵逼,没关系,下面我们用一个案例来串联前面的知识点,演示一下,认真阅读注释:
    
    
    
    
        //用new关键字创建一个Promise实例
        let pro = new Promise(function(resolve,reject){
            //假设condition的值为true
            let condition = true;
    
            if(condition){
                //调用操作成功方法
                resolve('操作成功');
                //状态:pending->fulfilled
            }else{
                //调用操作异常方法
                reject('操作异常');
                //状态:pending->rejected
            }
        });
    
        //用then处理操作成功,catch处理操作异常
        pro.then(function (res) {
    
            //操作成功的处理程序
            console.log(res)
    
        }).catch(function (error) {
    
            //操作失败的处理程序
            console.log(error)
    
        });
        //控制台输出:操作成功
    
    
    
            上面案例的注释十分详细,串联起了上面介绍的所有知识点:创建实例,状态转换,then方法和catch方法的使用。
    
    
    
            由于我们设置了变量condition的值为true,所以执行后控制台输出的结果是:“操作成功”。
    
     
    
            上面就是Promise用于处理操作异常的这个过程;但是,正如文章开头讲到的,如果多个操作之间层层依赖,我们用Promise又是怎么处理的呢?
    
    
    
    
    完整案例
            
    
            我们看看下面的案例,代码有点长,但是一点都不复杂:
    
    
    
    
        let pro = new Promise(function(resolve,reject){
    
            if(true){
                //调用操作成功方法
                resolve('操作成功');
            }else{
                //调用操作异常方法
                reject('操作异常');
            }
        });
    
        //用then处理操作成功,catch处理操作异常
        pro.then(requestA)
            .then(requestB)
            .then(requestC)
            .catch(requestError);
    
        function requestA(){
            console.log('请求A成功');
            return '请求B,下一个就是你了';
        }
        function requestB(res){
            console.log('上一步的结果:'+res);
            console.log('请求B成功');
            return '请求C,下一个就是你了';
        }
        function requestC(res){
            console.log('上一步的结果:'+res);
            console.log('请求C成功');
        }
        function requestError(){
            console.log('请求失败');
        }
    
        //打印结果:
        //请求A成功
        //上一步的结果:请求B,下一个就是你了
        //请求B成功
        //上一步的结果:请求C,下一个就是你了
        //请求C成功
    
     
    
            案例中,先是创建一个实例,还声明了4个函数,其中三个是分别代表着请求A,请求B,请求C;有了then方法,三个请求操作再也不用层层嵌套了。我们使用then方法,按照调用顺序,很直观地完成了三个操作的绑定,并且,如果请求B依赖于请求A的结果,那么,可以在请求A的程序用使用return语句把需要的数据作为参数,传递给下一个请求,案例中我们就是使用return实现传递参数给下一步操作的。
    
    
    
    
    更直观的图解
    
    
            如果你还是是懂非懂,没关系,前端君拼了,上图:
    
    
    
    
    
    
    
    
            图有点粗糙,但是能反应出上面程序的执行过程,帮助大家加深理解。
    
     
    
            除了提供了实例方法以外,Promise还提供了一些类方法,也就是不用创建实例,也可以调用的方法。
    
    
    
            下面,我们来学习几个重要的。
    
    
     Promise.all( )方法
    
    
            Promise.all( )方法:接受一个数组作为参数,数组的元素是Promise实例对象,当参数中的实例对象的状态都为fulfilled时,Promise.all( )才会有返回。
    
    
    
            我们来演示一下:
    
    
    
    
        //创建实例pro1
        let pro1 = new Promise(function(resolve){
            setTimeout(function () {
                resolve('实例1操作成功');
            },5000);
        });
        
        //创建实例pro2
        let pro2 = new Promise(function(resolve){
            setTimeout(function () {
                resolve('实例2操作成功');
            },1000);
        });
    
        
        Promise.all([pro1,pro2]).then(function(result){
            console.log(result);
        });
        //打印结果:["实例1操作成功", "实例2操作成功"]
    
    
    
            上述案例,我们创建了两个Promise实例:pro1和pro2,我们注意两个setTimeout的第二个参数,分别是5000毫秒和1000毫秒,当我们调用Promise.all( )方法的时候,会延迟到5秒才控制台会输出结果。
    
    
    
            因为1000毫秒以后,实例pro2进入了成功fulfilled状态;此时,Promise.all( )还不会有所行动,因为实例pro1还没有进入成功fulfilled状态;等到了5000毫秒以后,实例pro1也进入了成功fulfilled状态,Promise.all( )才会进入then方法,然后在控制台输出:["实例1操作成功","实例2操作成功"]。
    
    
    
            这个方法有什么用呢?一般这样的场景:我们执行某个操作,这个操作需要得到需要多个接口请求回来的数据来支持,但是这些接口请求之前互不依赖,不需要层层嵌套。这种情况下就适合使用Promise.all( )方法,因为它会得到所有接口都请求成功了,才会进行操作。
    
     
    
     Promise.race( )方法
            
    
            另一个类似的方法是Promise.race()方法:它的参数要求跟Promise.all( )方法一样,不同的是,它参数中的promise实例,只要有一个状态发生变化(不管是成功fulfilled还是异常rejected),它就会有返回,其他实例中再发生变化,它也不管了。
    
    
    
    
        //初始化实例pro1
        let pro1 = new Promise(function(resolve){
            setTimeout(function () {
                resolve('实例1操作成功');
            },4000);
        });
    
        //初始化实例pro2
        let pro2 = new Promise(function(resolve,reject){
            setTimeout(function () {
                reject('实例2操作失败');
            },2000);
        });
    
        Promise.race([pro2,pro1]).then(function(result){
            console.log(result);
        }).catch(function(error){
            console.log(error);
        });
        //打印结果:实例2操作失败
    
    
    
            同样是两个实例,实例pro1不变,不同的是实例pro2,这次我们调用的是失败函数reject。
    
    
    
            由于pro2实例中2000毫秒之后就执行reject方法,早于实例pro1的4000毫秒,所以最后输出的是:实例2操作失败。
  • 相关阅读:
    RIA Animation test.
    深入浅出REST
    HTTP header中的 Cachecontrol
    Silverlight操纵html元素
    Comparing Azure storage and SQL Data Services
    SharePoint 2010 集成Window Live 认证遇到的问题 part 2
    SharePoint2010 此工作簿未存储在 Excel Services 应用程序 中受信任的位置,因此无法打开。
    SharePoint2010 使用Designer开发工作流 如何引用其他列表的查阅项
    SharePoint 2010 item级的权限控制
    Infopath 2010 如何设计虚线底框应用于合同中的输入框
  • 原文地址:https://www.cnblogs.com/liulinjie/p/11023033.html
Copyright © 2011-2022 走看看