promise

什么是Promise

Promise是抽象异步处理对象以及对其进行各种操作的组件。 其详细内容在接下来我们还会进行介绍,Promise并不是从JavaScript中发祥的概念。

Promise最初被提出是在 E语言中, 它是基于并列/并行处理设计的一种编程语言。

现在JavaScript也拥有了这种特性,这就是本书所介绍的JavaScript Promise。

另外,如果说到基于JavaScript的异步处理,我想大多数都会想到利用回调函数。

Promise解决的问题


我相信每个前端都遇到过这样一个问题,当一个异步任务的执行需要依赖另一个异步任务的结果时,我们一般会将两个异步任务嵌套起来,这种情况发生一两次还可以忍,但是发生很多次之后,你的代码就会变成这个熊样:

    async1(function(){
        async2(function(){
            async3(function(
                async4(funciton(){
                    async5(function(){
                        //(╯°□°)╯︵┻━┻
                        //...
                    });
                });
            )); 
        });
    });

这就是所谓的回调地狱,代码层层嵌套,环环相扣,很明显,逻辑稍微复杂一些,这样的程序就会变得难以维护。

但去年ES2015的标准里,Promise的标准化,一定程度上解决了JavaScript的流程操作问题。

Promise的基本用法


Promise类似于 XMLHttpRequest,从构造函数 Promise 来创建一个新建新promise对象作为接口。

要想创建一个promise对象、可以使用new来调用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)
})

运行结果有两种情况,如下图


运行结果

先跟大家介绍一下Promsie的基础知识
Promise对象有三种状态,他们分别是:

  • pending:等待中或者进行中,表示还没得到结果
  • resolve(fulfilled):已经完成,表示得到了我们想要的结果,可以继续往下执行
  • rejected:也表示得到结果,但是由于结果并非我们希望的,因此拒绝执行
    这三种状态不受外界影响,而且状态只能从pending改变为resolved或者rejected,并且不可逆。

在Promise对象的构造函数中,接受一个函数作为参数,该函数就是用来处理Promise的状态变化的,该函数接受两个额外的函数resolve和reject,这两个函数分别代表将当前Promise置为fulfilled(解决)和rejected(拒绝)两个状态。

实际上Promise实例_promise是一个对象,不是一个函数。在声明的时候,Promise传递的参数函数会立即执行,因此Promise使用的正确姿势是在其外层再包裹一层函数。如下:

var run = funciton(){
  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的正常用法

一个Promise必须提供一个then方法来获取其值或原因。
Promise的then方法接受两个参数:promise.then(onFulfilled, onRejected)

then方法可以接受两个回调函数作为参数。第一个回调函数是Promise对象的状态变为resolved时调用,第二个回调函数是Promise对象的状态变为rejected时调用。其中,第二个函数是可选的,不一定要提供。这两个函数都接受Promise对象传出的值作为参数。

接着上面创建的函数run(),我们来进行对异步操作结果的处理:

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

如果异步操作获得了我们想要的结果,那我们将调用处理resolve的函数(即onFulfilled方法),也就是在then的第一个作为参数的函数中进行处理,获取数据;如果我们得到了错误的结果,调用处理reject的函数(即 onRejected方法),也就是在then函数的第二个作为参数的函数中进行处理,获取错误处理数据。

reject后的处理,除了可以在.then 的第二个参数中处理,还可以在 .catch 方法中设置想要调用的函数。

以下是将对reject的处理放到.catch方法中:

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

这样,一个次完整的Promise调用就结束了。对于Promise的then()方法,then总是会返回一个Promise实例:
promise2 = promise1.then(onFulfilled, onRejected);
因此我们可以像上面面那样接着对其返回值进行 .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方法可以无限调用下去。
    */

根据这个特性,我们就可以将相互依赖的多个异步逻辑,进行顺序管理。
下面举个例子:

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

//连续调用
run_a().then(function(data){
  //返回一个Promise实例
  return run_b(data);
}).then(function(data){
  return run_c(data);
}).then(function(data){
  console.log(data);
})

用 async/await 来处理异步

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

推荐阅读更多精彩内容