ES6的Promise:要优雅,也要浪漫

夏侯杰
• 阅读 2658

在ECMAScript 6标准中,Promise被正式列为规范,Promise,字面意思就是“许诺,承诺”,嘿,听着是不是很浪漫的说?我们来探究一下这个浪漫的Promise对象到底是如何许下承诺,又是如何兑现TA的诺言的。

1.许下一个Promise(承诺)

下面我们将通过一些简单的例子,来一步一步的探究Promise的含义,更重要的是,用心体会Ta的优雅和浪漫(PS:让程序猿体会浪漫,是不是难为大家了)

在ES6标准中被定义为一个构造函数,那好我们就先new一个对象出来看看。

var promise = new Promise(function(resolve,reject){
   //一个异步操作
    setTimeout(function(){
        let foo = 1;
        console.log('执行完成');
        resolve(foo);
    }, 2000);
});

上面的代码就可以看作是Promise给我们许下了一个承诺,不过,这特么到底是个啥意思呢?
构造函数Promise接收一个回调函数做参数,同时这个回调函数又接受2个function做参数,本例中分别起名叫resolvereject,分别代表异步操作执行成功后的操作,和异步操作执行失败后的操作
ES6标准中规定一个 Promise的当前状态必须为以下三种状态中的一种:

  • 进行中(Pending

  • 已完成(ResolvedFulfilled

  • 已失败(Rejected

下表简单总结了三种状态所代表的含义:

名称 含义 满足条件
Pending 进行中 操作正在执行,可以切换为Resolve或Rejected状态
Resolved 已完成 必须拥有一个不可变的终值,且不可以切换到其他状态
Rejected 已失败 必须拥有一个不可变的终值,且不可以切换到其他状态

当Promise的状态由pending状态,通过resolve函数改变为resolved,或者通过reject函数改变为rejected后,状态就凝固了,不会再变了,会一直保持这个结果。就算改变已经发生了,即使再对Promise对象添加回调函数,也会立即得到这个结果。

2.兑现你的承诺

最重要的不是看Ta怎么说,重要的是要看Ta怎么做。既然许下了承诺,就必须要兑现承诺。
下面就要介绍Promise.prototype.then()方法,来访问其当前值、终值和据因。它的作用是为Promise实例添加状态改变时的回调函数then方法接收2个参数,第一个参数是Resolved状态的回调函数,第二个参数(可选)是Rejected状态的回调函数。
废话不多说直接上示例代码:

function foo (a){
  var promise = new Promise(function(resolve,reject){
      setTimeout(function(){
          if(a > 0){
            resolve(a);
          }else {
            reject(a);
          }
      }, 2000);
  });
  return promise;
}

foo(1).then(function(a){
  console.log("success",a+1);
},function(a){
  console.log("error",a);
});

上面的代码中,简单设定一个定时任务模拟异步操作,当a>0时,认为操作成功,则在then方法中执行第一个回调函数,输出success;当传入的值 a<0时,就被认为操失败,则then方法执行第二个回调函数,输出error。看到这里,我们可能会感觉到Promise 和我们之前用的回调函数有点相似,但是貌似Promise是用同步的写法来处理异步的操作。简单来讲,Promise就是能把原来的回调写法分离出来,在异步操作执行完后,用链式调用的方式执行回调函数。
我们了解了以上的基本原理,以后碰到需要传递多个callback的情况的时候,就可以使用Promise实现链式调用,从而避免陷入回调地狱中。
示例代码:

function foo(a) {
  ++a;
  console.log(a);
  var promise = new Promise(function (resolve, reject) {
    setTimeout(function () {
      if (a > 0) {
        resolve(a);
      } else {
        reject(a);
      }
    }, 2000);
  });
  return promise;
}
function foo2(a) {
  ++a;
  console.log(a);
  var promise = new Promise(function (resolve, reject) {
    setTimeout(function () {
      if (a > 1) {
        resolve(a);
      } else {
        reject(a);
      }
    }, 2000);
  });
  return promise;
}
function foo3(a) {
  ++a;
  console.log(a);
  var promise = new Promise(function (resolve, reject) {
    setTimeout(function () {
      if (a > 2) {
        resolve(a);
      } else {
        reject(a);
      }
    }, 2000);
  });
  return promise;
}
function foo4(a) {
  ++a;
  console.log(a);
  var promise = new Promise(function (resolve, reject) {
    setTimeout(function () {
      if (a > 3) {
        resolve(a);
      } else {
        reject(a);
      }
    }, 2000);
  });
  return promise;
}

//链式调用各个处理函数
foo(1).then(function (a) {
  return foo2(a);
})
.then(function (a) {
  return foo3(a);
})
.then(function (a) {
  return foo4(a);
})

3.承诺兑现不了咋办

并不是所有的承诺都会被兑现,就好像小时候父母都说帮我们存压岁钱以后还给我们一样。Promise中也是如此,总会有我们意想不到的差错发生导致无法按照预期的函数进行执行,
所以Promise提供了一个名为catch的方法帮我们解决这个问题。
Promise.prototype.catch()方法有2个作用,第一个作用,就是和then方法中的第二个参数作用相同,就是当状态切换成rejected时执行相应的操作,例如第一个例子中换个写法:

foo(1)
.then(function(a){
  console.log("success",a+1);
})
.catch(function(a){
  console.log("error",a);
});

作用和原来完全一致。
第二个作用就是在执行resolve的回调(也就是上面then中的第一个参数)时,如果抛出异常了(代码出错了),那么并不会报错卡死js,而是会进到这个catch方法中。

4.玩儿了命也要兑现承诺

要是你在生活中真遇到一个肯为你玩儿命的人。。。。。
关我毛事,劳资单身狗,秀恩爱的请移步他处。。。。。
Promise中提供了Promise.all方法,注意all方法是直接定义在Promise上的而不是原型链中。主要作用就是提供了并行执行异步操作的能力,让程序玩了命的跑起来。

var promise = Promise.all([p1, p2, p3]).then(function (p) {
  console.log(p);
});

Promise.all会将多个Promise的实例,包装成一个新的Promise实例,然后传递给后面的then方法。

Promise.all方法的参数可以不是数组,但必须具有Iterator接口,且返回的每个成员都是Promise实例

兼容性

说了这么多,哇塞这么优雅的特性一定要用起来啊,但是在激动之余,毕竟Promise是ES6标准中的新增对象,所以还是得冷静下来检查一下Promise对象的兼容性如何,
ES6的Promise:要优雅,也要浪漫
通过在can I use...网站上获取到的统计数据看来,Promise对象的兼容性不是很好,目前只有在比较新的主流浏览器中才得到全面支持,而且我们注意到微软的所有IE浏览器均不支持该对象,只有在win10中的Edge浏览器中才获得支持。看来我们在准备使用Promise的时候,还是要视自己的实际开发环境而定。

关于ES6的其他特性的最新支持情况,请点击这里

总结

Promise作为ES6标准中一个比较新鲜的特性,还有其他方法这里没有讲到,比如resolve,reject,race等,受限于水平与时间精力,今天暂时先写这么多,以后有时间再继续补充,对于文中的错误和不足,欢迎大家指出讨论,共同学习进步(虽然我不一定看。。。。逃。。)

附:在GitHub上阅读请点击

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Stella981 Stella981
3年前
Javascript 中的神器——Promise
_摘要:_ 回调函数真正的问题在于他剥夺了我们使用return和throw这些关键字的能力。而Promise很好地解决了这一切回调函数真正的问题在于他剥夺了我们使用return和throw这些关键字的能力。而Promise很好地解决了这一切Promise概念所谓Promise,就是ES6原生提供的一个
Stella981 Stella981
3年前
ES6中的Promise和Generator详解
简介ES6中除了上篇文章讲过的语法新特性和一些新的API之外,还有两个非常重要的新特性就是Promise和Generator,今天我们将会详细讲解一下这两个新特性。Promise什么是PromisePromise是异步编程的一种解决方案,比传统的解决方案“回调函数和事件”更合理和更强大。所谓P
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Stella981 Stella981
3年前
Promise进一步阅读
下面是几篇比较好的Promise文章:\1\Promise是怎么工作的,http://wengeezhang.com/?p13(https://www.oschina.net/action/GoToLink?urlhttp%3A%2F%2Fwengeezhang.com%2F%3Fp%3D13)\2\JavaScript进阶之路
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
美凌格栋栋酱 美凌格栋栋酱
5个月前
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(
Promise规范与原理解析 | 京东物流技术团队
Promise对象用于清晰的处理异步任务的完成,返回最终的结果值,本次分享主要介绍Promise的基本属性以及Promise内部的基础实现,能够帮我们更明确使用场景、更快速定位问题。
Python进阶者 Python进阶者
1年前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这
京东云开发者 京东云开发者
7个月前
Promise规范与原理解析
作者:京东物流孙琦摘要Promise对象用于清晰的处理异步任务的完成,返回最终的结果值,本次分享主要介绍Promise的基本属性以及Promise内部的基础实现,能够帮我们更明确使用场景、更快速定位问题。Promise出现的原因首先我们先来看一段代码:异步