ES6中的Promise用法
Node的产生,大大推动了Javascript
这门语言在服务端的发展,使得前端人员可以以很低的门槛转向后端开发。
当然,这并不代表迸发成了全栈。全栈的技能很集中,绝不仅仅是前端会写一些HTML
和一些交互,后台熟悉数据库的增删查改。
想必接触过Node的人都知道,Node是以异步(Async)回调著称的,其异步性提高了程序的执行效率,但同时也减少了程序的可读性。如果我们有几个异步操作,并且后一个操作需要前一个操作返回的数据才能执行,这样按照Node的一般执行规律,要实现有序的异步操作,通常是一层加一层嵌套下去。
为了解决这个问题,ES6提出了Promise
的实现。
含义
Promise 对象用于一个异步操作的最终完成(或失败)及其结果值的表示。简单点说,它就是用于处理异步操作的,异步处理成功了就执行成功的操作,异步处理失败了就捕获错误或者停止后续操作。
它的一般表示形式为:
new Promise(
/* executor */
function(resolve, reject) {
if (/* success */) {
// ...执行代码
resolve();
} else { /* fail */
// ...执行代码
reject();
}
}
);
其中,Promise中的参数executor
是一个执行器函数,它有两个参数resolve
和reject
。它内部通常有一些异步操作,如果异步操作成功,则可以调用resolve()来将该实例的状态置为fulfilled
,即已完成的,如果一旦失败,可以调用reject()来将该实例的状态置为rejected
,即失败的。
我们可以把Promise对象看成是一条工厂的流水线,对于流水线来说,从它的工作职能上看,它只有三种状态,一个是初始状态(刚开机的时候),一个是加工产品成功,一个是加工产品失败(出现了某些故障)。同样对于Promise对象来说,它也有三种状态:
pending
初始状态,也称为未定状态,就是初始化Promise时,调用executor执行器函数后的状态。fulfilled
完成状态,意味着异步操作成功。rejected
失败状态,意味着异步操作失败。
它只有两种状态可以转化,即
操作成功
pending -> fulfilled操作失败
pending -> rejected
并且这个状态转化是单向的,不可逆转,已经确定的状态(fulfilled/rejected)无法转回初始状态(pending)。
方法
Promise.prototype.then()
Promise对象含有then方法,then()调用后返回一个Promise对象,意味着实例化后的Promise对象可以进行链式调用,而且这个then()方法可以接收两个函数,一个是处理成功后的函数,一个是处理错误结果的函数。
如下:
var promise1 = new Promise(function(resolve, reject) {
// 2秒后置为接收状态
setTimeout(function() {
resolve('success');
}, 2000);
});
promise1.then(function(data) {
console.log(data); // success
}, function(err) {
console.log(err); // 不执行
}).then(function(data) {
// 上一步的then()方法没有返回值
console.log('链式调用:' + data); // 链式调用:undefined
}).then(function(data) {
// ....
});
在这里我们主要关注promise1.then()方法调用后返回的Promise对象的状态,是pending
还是fulfilled
,或者是rejected
?
返回的这个Promise对象的状态主要是根据promise1.then()方法返回的值,大致分为以下几种情况:
如果then()方法中返回了一个参数值,那么返回的Promise将会变成接收状态。
如果then()方法中抛出了一个异常,那么返回的Promise将会变成拒绝状态。
如果then()方法调用resolve()方法,那么返回的Promise将会变成接收状态。
如果then()方法调用reject()方法,那么返回的Promise将会变成拒绝状态。
如果then()方法返回了一个未知状态(pending)的Promise新实例,那么返回的新Promise就是未知状态。
如果then()方法没有明确指定的resolve(data)/reject(data)/return data时,那么返回的新Promise就是接收状态,可以一层一层地往下传递。
转换实例如下:
var promise2 = new Promise(function(resolve, reject) {
// 2秒后置为接收状态
setTimeout(function() {
resolve('success');
}, 2000);
});
promise2
.then(function(data) {
// 上一个then()调用了resolve,置为fulfilled态
console.log('第一个then');
console.log(data);
return '2';
})
.then(function(data) {
// 此时这里的状态也是fulfilled, 因为上一步返回了2
console.log('第二个then');
console.log(data); // 2
return new Promise(function(resolve, reject) {
reject('把状态置为rejected error'); // 返回一个rejected的Promise实例
});
}, function(err) {
// error
})
.then(function(data) {
/* 这里不运行 */
console.log('第三个then');
console.log(data);
// ....
}, function(err) {
// error回调
// 此时这里的状态也是fulfilled, 因为上一步使用了reject()来返回值
console.log('出错:' + err); // 出错:把状态置为rejected error
})
.then(function(data) {
// 没有明确指定返回值,默认返回fulfilled
console.log('这里是fulfilled态');
});
Promise.prototype.catch()
catch()方法和then()方法一样,都会返回一个新的Promise对象,它主要用于捕获异步操作时出现的异常。因此,我们通常省略then()方法的第二个参数,把错误处理控制权转交给其后面的catch()函数,如下:
var promise3 = new Promise(function(resolve, reject) {
setTimeout(function() {
reject('reject');
}, 2000);
});
promise3.then(function(data) {
console.log('这里是fulfilled状态'); // 这里不会触发
// ...
}).catch(function(err) {
// 最后的catch()方法可以捕获在这一条Promise链上的异常
console.log('出错:' + err); // 出错:reject
});
Promise.all()
Promise.all()接收一个参数,它必须是可以迭代的,比如数组。
它通常用来处理一些并发的异步操作,即它们的结果互不干扰,但是又需要异步执行。它最终只有两种状态:成功或者失败。
它的状态受参数内各个值的状态影响,即里面状态全部为fulfilled
时,它才会变成fulfilled
,否则变成rejected
。
成功调用后返回一个数组,数组的值是有序的,即按照传入参数的数组的值操作后返回的结果。如下:
// 置为fulfilled状态的情况
var arr = [1, 2, 3];
var promises = arr.map(function(e) {
return new Promise(function(resolve, reject) {
resolve(e * 5);
});
});
Promise.all(promises).then(function(data) {
// 有序输出
console.log(data); // [5, 10, 15]
console.log(arr); // [1, 2, 3]
});
// 置为rejected状态的情况
var arr = [1, 2, 3];
var promises2 = arr.map(function(e) {
return new Promise(function(resolve, reject) {
if (e === 3) {
reject('rejected');
}
resolve(e * 5);
});
});
Promise.all(promises2).then(function(data) {
// 这里不会执行
console.log(data);
console.log(arr);
}).catch(function(err) {
console.log(err); // rejected
});
Promise.race()
Promise.race()和Promise.all()类似,都接收一个可以迭代的参数,但是不同之处是Promise.race()的状态变化不是全部受参数内的状态影响,一旦参数内有一个值的状态发生的改变,那么该Promise的状态就是改变的状态。就跟race
单词的字面意思一样,谁跑的快谁赢。如下:
var p1 = new Promise(function(resolve, reject) {
setTimeout(resolve, 300, 'p1 doned');
});
var p2 = new Promise(function(resolve, reject) {
setTimeout(resolve, 50, 'p2 doned');
});
var p3 = new Promise(function(resolve, reject) {
setTimeout(reject, 100, 'p3 rejected');
});
Promise.race([p1, p2, p3]).then(function(data) {
// 显然p2更快,所以状态变成了fulfilled
// 如果p3更快,那么状态就会变成rejected
console.log(data); // p2 doned
}).catch(function(err) {
console.log(err); // 不执行
});
Promise.resolve()
Promise.resolve()接受一个参数值,可以是普通的值
,具有then()方法的对象
和Promise实例
。正常情况下,它返回一个Promise对象,状态为fulfilled
。但是,当解析时发生错误时,返回的Promise对象将会置为rejected
态。如下:
// 参数为普通值
var p4 = Promise.resolve(5);
p4.then(function(data) {
console.log(data); // 5
});
// 参数为含有then()方法的对象
var obj = {
then: function() {
console.log('obj 里面的then()方法');
}
};
var p5 = Promise.resolve(obj);
p5.then(function(data) {
// 这里的值时obj方法里面返回的值
console.log(data); // obj 里面的then()方法
});
// 参数为Promise实例
var p6 = Promise.resolve(7);
var p7 = Promise.resolve(p6);
p7.then(function(data) {
// 这里的值时Promise实例返回的值
console.log(data); // 7
});
// 参数为Promise实例,但参数是rejected态
var p8 = Promise.reject(8);
var p9 = Promise.resolve(p8);
p9.then(function(data) {
// 这里的值时Promise实例返回的值
console.log('fulfilled:'+ data); // 不执行
}).catch(function(err) {
console.log('rejected:' + err); // rejected: 8
});
Promise.reject()
Promise.reject()和Promise.resolve()正好相反,它接收一个参数值reason
,即发生异常的原因。此时返回的Promise对象将会置为rejected
态。如下:
var p10 = Promise.reject('手动拒绝');
p10.then(function(data) {
console.log(data); // 这里不会执行,因为是rejected态
}).catch(function(err) {
console.log(err); // 手动拒绝
}).then(function(data) {
// 不受上一级影响
console.log('状态:fulfilled'); // 状态:fulfilled
});
总之,除非Promise.then()方法内部抛出异常或者是明确置为rejected态,否则它返回的Promise的状态都是fulfilled态,即完成态,并且它的状态不受它的上一级的状态的影响。
总结
大概常用的方法就写那么多,剩下的看自己实际需要再去了解。
解决Node回调地狱的不止有Promise
,还有Generator
和ES7提出的Async
实现。
方法不在多,而在于精。
ES6中的Promise用法的更多相关文章
- es6中的promise对象
Promise是异步里面的一种解决方案,解决了回调嵌套的问题,es6将其进行了语言标准,同意了用法,提供了`promise`对象, promise对象有三种状态:pending(进行中) .Resol ...
- 深入理解 JavaScript 异步系列(3)—— ES6 中的 Promise
第一部分,Promise 加入 ES6 标准 原文地址 http://www.cnblogs.com/wangfupeng1988/p/6515855.html 未经作者允许不得转载! 从 jquer ...
- [转]JS - Promise使用详解2(ES6中的Promise)
原文地址:https://www.hangge.com/blog/cache/detail_1638.html 2015年6月, ES2015(即 ECMAScript 6.ES6) 正式发布.其中 ...
- ES6中的Promise和Generator详解
目录 简介 Promise 什么是Promise Promise的特点 Promise的优点 Promise的缺点 Promise的用法 Promise的执行顺序 Promise.prototype. ...
- es6中的Promise学习
关于Promise Promise实例一旦被创建就会被执行 Promise过程分为两个分支:pending=>resolved和pending=>rejected Promise状态改变后 ...
- ES6中的Promise使用方法与总结
在javascript中,代码是单线程执行的,对于一些比较耗时的IO操作,都是通过异步回调函数来实现的. 但是这样会存在一个问题,当下一个的操作需要上一个操作的结果时,我们只能把代码嵌到上一个操作的回 ...
- ES6中bind(this)用法说明
在使用 React 中的 Class extends写法,如果 onClick 绑定一个方法就需要 bind(this),如果使用React.createClass 方法就不需要 解析: React. ...
- ES6中set的用法回顾
ES6中的set类似一个数组,但是其中的值都是唯一的,Set本身是一个构造函数,用来生成 Set 数据结构. set函数可以接受一个数组作为参数,用来初始化: const set = new Set( ...
- 理解ES6中的Promise
一.Promise的作用 在ajax请求数据的过程中,我们可以异步拿到我们想要的数据,然后在回调中做相应的数据处理. 这样做看上去并没有什么麻烦,但是如果这个时候,我们还需要做另外一个ajax请求,这 ...
随机推荐
- PHPStorm调试PHP代码~实际操作+mark~~
因为wamp自己已经下载了xdebug,只要配置开启就行了. 1. 配置php.ini(有就打开注释,没有就加上) XDEBUG Extension[xdebug]zend_extension =&q ...
- SSM整合开发
导入开发包 asm-3.2.0.RELEASE.jar asm-3.3.1.jar c3p0-0.9.jar cglib-2.2.2.jar com.springsource.net.sf.cglib ...
- 为bookStore添加权限【动态代理和注解】
前言 目前为止,我们已经学习了动态代理技术和注解技术了.于是我们想要为之前的bookStore项目添加权限控制-.. 只有用户有权限的时候,后台管理才可以进行相对应的操作-.. 实现思路 之前我们做权 ...
- [01] Servlet是什么
1.Servlet是什么 Servlet(Server Applet),全称Java Servlet,是用Java编写的服务器端程序.其主要功能在于交互式地浏览和修改数据,生成动态Web内容. 1.1 ...
- Apache Spark 2.2.0 中文文档 - Spark RDD(Resilient Distributed Datasets)论文 | ApacheCN
Spark RDD(Resilient Distributed Datasets)论文 概要 1: 介绍 2: Resilient Distributed Datasets(RDDs) 2.1 RDD ...
- android动画的实现过程
先上自己的测试代码,有参考apidemo中的AnimationDrawable中的方法 public class AnimateActivity extends Activity { @Overrid ...
- Angular2响应式表单
本文将半翻译半总结的讲讲ng2官网的另一个未翻译高级教程页面. 原文地址. 文章目的是使用ng2提供的响应式表单技术快速搭出功能完善丰富的界面表单组件. 响应式表单是一项响应式风格的ng2技术,本文将 ...
- 【转】开源中国上看到的一个vim的自动配置的好东西,分享下
https://www.oschina.net/p/onekey-to-vim-ide 变量有高亮,竖行上有直线定位,对python的支持效果更佳,从事C/C++开发的程序员使用也不错.
- Linux的硬盘使用情况、挂载、SSD挂载(查看df -h不能看到的卷)
linux上的盘和window的有区别,磁盘空间必须挂载在目录上,要不然没用 对与新增的硬盘.SSD固态硬盘.挂载到linux上的操作如下: df -h #显示目前在Linux系统上的文件系 ...
- hibernate学习手记(2)
1.javax.persistence.TransactionRequiredException: no transaction is in progress 出现该问题是我没有开启事务,我是在保存之 ...