Promise

Javascript是一种单线程的语言,所有的代码必须按照所谓的“自上而下”的顺序来执行。本特性带来的问题是,一些将来的、未知的操作,必须异步实现。本文将讨论一个比较常见的异步解决方案——Promise。

一 Promise解决的问题

当一个异步任务的执行需要依赖另一个异步任务的结果时,我们一般会将两个异步任务嵌套起来,这种情况发生一两次还可以忍,但是发生很多次之后 , 会出现回调地狱问题,导致代码层层嵌套,环环相扣,很明显,逻辑稍微复杂一些,这样的程序就会变得难以维护。
对于这种情况,Promise的标准化,一定程度上解决了JavaScript的流程操作问题。

二 Promise的基本用法

现代浏览器都已经实现对promise的支持, 那么,我们可以由此得到一个Promise构造函数。
根据Promise构造函数,将新建一个Promise的实例

var _promise = new Promise(function(resolve, reject){
        setTimeout(function(){
            var rand = Math.random();
            if(rand<0.5){
                resolve("resolve" + rand);
            }else{
                reject("reject" + rand);
            }
        },1000);
    });

由上所示,Promise的构造函数接收一个函数作为参数,该函数接受两个额外的函数,resolve和reject,这两个函数分别代表将当前Promise置为fulfilled(解决)和rejected(拒绝)两个状态。Promise正是通过这两个状态来控制异步操作的结果。接下来我们将讨论Promise的用法,实际上Promise上的实例_promise是一个对象,不是一个函数。在声明的时候,Promise传递的参数函数会立即执行,因此Promise使用的正确姿势是在其外层再包裹一层函数。

var run = function(){
        var _promise = new Promise(function(resolve, reject){
            setTimeout(function(){
                var rand = Math.random();
                if(rand<0.5){
                    resolve("resolve" + rand);
                }else{
                    reject("reject" + rand);
                }
            },1000);
        });
        return _promise;
    }

    run();

对异步操作结果的处理

每个Promise的实例对象,都有一个then的方法,这个方法就是用来处理之前各种异步逻辑的结果。

run().then(function(data){
        console.log(data);
    });

Promise的用处,实际上是在于多重异步操作相互依赖的情况下,对于逻辑流程的控制。Promise正是通过对两种状态的控制,以此来解决流程的控制。请看如下代码:

run().then(function(data){
    //处理resolve的代码
    cosnole.log("Promise被置为resolve",data);
},function(data){
    //处理reject的代码
    cosnole.log("程序被置为了reject",data);
})

如果异步操作获得了我们想要的结果,那我们将调用resolve函数,在then的第一个作为参数的匿名函数中可以获取数据,如果我们得到了错误的结果,调用reject函数,在then函数的第二个作为参数的匿名函数中获取错误处理数据。 这样,一个次完整的Promise调用就结束了。对于Promise的then()方法,then总是会返回一个Promise实例,因此你可以一直调用then,形如run().then().then().then().then().then()..... 在一个then()方法调用异步处理成功的状态时,你既可以return一个确定的“值”,也可以再次返回一个Promise实例,当返回的是一个确切的值的时候,then会将这个确切的值传入一个默认的Promise实例,并且这个Promise实例会立即置为fulfilled状态,以供接下来的then方法里使用。如下所示:

run().then(function(data){
        console.log("第一次",data);
        return data;
    }).then(function(data){
        console.log("第二次",data);
        return data;
    }).then(function(data){
        console.log("第三次",data);
        return data;
    });
    /* 异步处理成功的打印结果:
        第一次 resolve0.49040459200760167d.js:18 
        第二次 resolve0.49040459200760167d.js:21 
        第三次 resolve0.49040459200760167
        由此可知then方法可以无限调用下去。
    */

根据这个特性,我们就可以将相互依赖的多个异步逻辑,进行比较顺序的管理 , 解决地狱回调的问题。
下面举一个拥有3个异步操作的例子。

//第一个异步任务
    function run_a(){
        return new Promise(function(resolve, reject){
            //假设已经进行了异步操作,并且获得了数据
            resolve("step1");
        });
    }
    //第二个异步任务
    function run_b(data_a){
        return new Promise(function(resolve, reject){
            //假设已经进行了异步操作,并且获得了数据
            console.log(data_a);
            resolve("step2");
        });
    }
    //第三个异步任务
    function run_c(data_b){
        return new Promise(function(resolve, reject){
            //假设已经进行了异步操作,并且获得了数据
            console.log(data_b);
            resolve("step3");
        });
    }

    //连续调用
    run_a().then(function(data){
        return run_b(data);
    }).then(function(data){
        return run_c(data);
    }).then(function(data){
        console.log(data);
    });

    /*运行结果
      step1
      step2
      step3
    */

三 异步操作拒绝及中断调用链

前文提到过,then方法可以接收两个匿名函数作为参数,第一个参数是Promise置为fulfilled状态后的回调,第二个是置为rejected状态的回调。在很多情况下,如果连续的几个异步任务,其中某个异步任务处理失败,那么接下来的几个任务很大程度上就不需要继续处理了,那么我们该如何终止then的调用链呢?在Promsie的实例上,除了then方法外,还有一个catch方法,catch方法的具体作用,我们沿用上面的代码,将run_a()改造一下来看:

//修改run_a的一步操作可能存在拒绝状态
    function run_a(){
        return new Promise(function(resolve, reject){
            setTimeout(function(){
                if(Math.random()>.5){
                    resolve("step1");
                }else{
                    reject("error");
                }
            },1000);
        });
    }

    //这样做不会中断
    run_a().then(function(data){
        return run_b(data);
    },function(data){
        //如果是这样处理rejected状态,并不会中断调用链
        return data;
    }).then(function(data){
        return run_c(data);
    }).then(function(data){
        console.log(data);
    });

    //在调用链的末尾加上catch方法,当某个环节的Promise的异步处理出错时,将中断其后的调用,直接跳到最后的catch
    run_a().then(function(data){
        return run_b(data);
    }).then(function(data){
        return run_c(data);
    }).then(function(data){
        console.log(data);
    }).catch(function(e){
        //rejected的状态将直接跳到catch里,剩下的调用不会再继续
        console.log(e);
    });

以上代码简单描述了如何中断链式调用,值得注意的是,catch方法还有try catch的作用,也就是说,then里面的逻辑代码如果出现了错误,并不会在控制台抛出,而是会直接有catch捕获。

四 promise的方法拓展

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,772评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,458评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,610评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,640评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,657评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,590评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,962评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,631评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,870评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,611评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,704评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,386评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,969评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,944评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,179评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,742评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,440评论 2 342