zoukankan      html  css  js  c++  java
  • 理解ES6中的Promise

    一、Promise的作用

    在ajax请求数据的过程中,我们可以异步拿到我们想要的数据,然后在回调中做相应的数据处理。
    这样做看上去并没有什么麻烦,但是如果这个时候,我们还需要做另外一个ajax请求,这个新的ajax请求的其中一个参数,得从上一个ajax请求中获取,这个时候我们就需要在回调函数中再写一个异步请求,然后在这个异步函数的回调函数里在写相应的数据处理。要是连续嵌套个三四层,往往就很恶心了。
    写起来就像下面这样:

    $.ajax({
        type:'get',
        url:'url_1', 
        data: 'data'
        success : function(res){
            //相应的数据处理
            var data = res.data
            $.ajax({
                type:'get',
                url:'url_2', 
                data: data
                success : function(res){
                    //相应的数据处理
                    $.ajax({
                        type:'get',
                        url:'url_3', 
                        data: data
                        success : function(res){
                            //相应的数据处理
                        }
                    })
                }
            })
        }
    })
    

    在这种情况下Promise就能发挥它的威力了;

    二、来一个实例

    先不谈语法,下面先来一个实例,建立感性的认识

    <!DOCTYPE html>
    <html>
        <head lang="en">
            <meta charset="UTF-8">
            <title></title>
            <script src="http://libs.baidu.com/jquery/2.0.0/jquery.js"></script>
        </head>
        <body>
        </body>
        <script>
            function a(data){
                return new Promise(function(resolve,reject){
                    console.log("我是从上一个回调函数里传过来的数据",data) ;
                    $.ajax({
                        type:'post',
                        dataType: 'jsonp',
                        url:'http://api.money.126.net/data/feed/0000001,1399001',   //jsonp跨域调用上证与深证的股票指数
                        data:{
                        },
                        success : function(res){
                            console.log(res) ;
                            resolve(res) ;
                        },
                        error:function(res){
                            console.log("Error:") ;
                            console.log(res) ;
                            reject(res) ;
                        }
                    })
                });
            }
            function b(data){
                return new Promise(function(resolve,reject){
                    console.log("我是从上一个回调函数里传过来的数据",data) ;
                    $.ajax({
                        type:'post',
                        dataType: 'jsonp',
                        url:'https://api.douban.com/v2/movie/top250',  //跨域调用豆top250的电影
                        success : function(res){
                            console.log(res) ;
                            resolve(res) ;
                        },
                        error:function(res){
                            console.log("Error:") ;
                            console.log(res) ;
                            reject(res)
                        }
                    })
                });
            }
            a().then(b).then(a).then(b).catch(function(a){console.log("final Error:",a)}) ;
        </script>
    </html>
    

    打印结果如下所示:
    Alt text

    可以发现,Promise 通过简单的链式调用就能得到之前多层回调才能达成的效果;而且从代码的结构来看,有效地减小了各个请求之间的耦合;

    三、深入Promise

    别的不谈,先打印一下 Promise , console.dir(Promise) , 看看它究竟是哪号人物:

    Alt text

    原来 Promise 本身是一个构造函数,自己身上有 allrejectresolve 这几个的方法,在其 prototype 上有 thencatch 这两个方法。那么用Promise new出来的对象也会有 thencatch 这两个方法。

    四、注意上面实例中的resolve与reject

    1、我们发现,在 new Promise(function(resolve,reject){}) 里传了两个方法 resolvereject 作为参数,这两个方法通常会在函数的回调里被用到。一旦执行到resolve() 或者 reject() ,那么这个函数会停止执行,然后触发后面的 then() 或者 catch() 方法。准确一点来说,执行到resolve() 会触发 then() 方法,执行到 reject() 会触发 catch() 方法。

    2、resolvereject 方法里可以传入参数 ,就像 resolve(data)reject(data) 。 如果这样做 ,那么在后面的 then() 或者 catch() 里传入一个带参数的函数 , 就像 then(function(data){}) 或者 catch(function(data){}) , 就能得到 data 的数据 。

    3、说的再专业一些,Promise 对象有三种状态,他们分别是:

    • pending: 等待中,或者进行中,表示还没有得到结果
    • resolved(Fulfilled): 已经完成,表示得到了我们想要的结果,可以继续往下执行
    • rejected: 也表示得到结果,但是由于结果并非我们所愿,因此拒绝执行

    这三种状态不受外界影响,而且状态只能从 pending 改变为 resolved 或者rejected ,并且不可逆。在 Promise 对象的构造函数中,resolvereject 就是用来处理Promise的状态变化。
    一般来说,调用 resolvereject 以后,Promise 的使命就完成了,后继操作应该放到 then 或者 catch 方法里面,而不应该直接写在 resolve()reject() 的后面 (事实的情况是,resolve()reject() 的后面的代码也不会执行)

    五、new Promise() 里的函数是立刻执行的

    需要注意的的是,new Promise() 里的函数是立刻执行的 ,也就是说 ,当你执行下面这段代码时,就已经开始执行异步请求了:

    <script>
    new Promise(function(resolve,reject){
        $.ajax({
            type:'post',
            dataType: 'jsonp',
            url:'http://api.money.126.net/data/feed/0000001,1399001',
            data:{
            },
            success : function(res){
                console.log(res) ;
                resolve(res) ;
            },
            error:function(res){
                reject(res) ;
            }
        })
    });
    </script>
    

    这也是为什么,在上面第二段的实例中,需要用 a()b() 函数把 new Promise() 给包起来

    六、then() 函数的返回值一定是 Promise 对象

    还需要注意的的是,then() 函数的返回值一定是 Promise 对象,哪怕手动 return 一个值也无济于事,如下面的代码,照样能运行成功:

    a().then(function (){console.log("hello");return 1}).then(b) ;
    

    这也解释了为什么我们可以链式调用 then() 函数。

    七、Promise.all()Promise.race()的用法

    想要从两个不同的 ajax 请求里分别获得信息,这两个任务是可以并行执行的,就可以用 Promise.all() 实现:

    <script>
    var p1 = function(){
        return new Promise(function (resolve, reject) {
            setTimeout(resolve, 500, 'P1');
        });
    } ;
    var p2 = function(){
        return new Promise(function (resolve, reject) {
            setTimeout(resolve, 1000, 'P2');
        });
    } ;
    // 同时执行p1和p2,并在它们都完成后执行then
    var start = function(){
        Promise.all([p1(), p2()]).then(function (results) {
            console.log(results); // 获得一个Array: ['P1', 'P2']
        });
    }
    </script>
    

    有些时候,多个异步任务是为了容错。比如,分别发两个不同的 ajax 请求读取用户的个人信息,只需要获得先返回的结果即可,这种情况下,就可以用Promise.race() 实现:

    <script>
    var p1 = function(){
        return new Promise(function (resolve, reject) {
            setTimeout(resolve, 500, 'P1');
        });
    } ;
    var p2 = function(){
        return new Promise(function (resolve, reject) {
            setTimeout(resolve, 1000, 'P2');
        });
    } ;
    var start = function(){
        Promise.all([p1(), p2()]).then(function (results) {
            console.log(results); // 'P1'
        });
    }
    </script>
    

    由于 p1 执行较快,Promisethen() 将获得结果 'P1'p2 仍在继续执行,但执行结果将被丢弃。

    如果我们组合使用Promise,就可以把很多异步任务以并行和串行的方式组合起来执行。

    参考文献:
    阮一峰ES6入门
    廖雪峰的官方网站
    sitepoint
    "吕大豹"的博客园
    原文地址:
    王玉略的个人网站

  • 相关阅读:
    一些图形API函数收录
    VC6.0常见编译错误及解决方法
    Google Test Primer(入门)(六) 结束部分
    转帖:C++程序内存泄露检测
    Google Test Primer(四)——简单测试
    Android Snippet
    DCAApp 和 DXPApp 类的探索
    WEB(Javascript)远程调用方案清单
    做一个treeview dropdownlist 最近会放上来
    DotLucene:37行代码全文搜索
  • 原文地址:https://www.cnblogs.com/wangyulue/p/7718554.html
Copyright © 2011-2022 走看看