ES6 - Note5:Promise
1.Promise介绍
Promise最早是社区提出和实现,后面ES6将其写入标准,并原生提供Promise对象,是一种异步编程的解决方案,具体的概念大家可以去查看相关的资料。传统上处理异步都是以callback回调函数的方式完成,但是当回调嵌套的太多,便会使程序很难理解,如下所示
function a(cb){
console.log('a...');
cb('a');
}
function b(cb){
console.log('b...');
cb('b');
}
function c(cb){
console.log('c...');
cb('c');
}
a(() => b( () => c( () => {}) ));
a...
b...
c...
如果后面还有基于C函数的输出结果的逻辑,回调将是很大的困恼。
而使用Promise来处理这种异步回调将会非常的直观,Promise以同步的操作完成异步的处理,如下所示
function a(){
console.log('a...');
return 'a output';
}
function b(res){
console.log('b...');
console.log('get A:'+res);
return "b output";
}
function c(res){
console.log('c...');
console.log('get B:'+res);
}
new Promise((resolve,reject) => {setTimeout(resolve,1000)}).then(a).then(b).then(c);
Promise { <state>: "pending" }
a...
b...
get A:a output
c...
get B:b output
2.Promise的用法
Promise是一个构造函数,接收一个函数参数,该函数接收两个函数作为参数,分别是resolve,reject。这两个函数由Promise自己提供,无需自己部署。resolve函数将Promise的状态从'Pending'转为'Resolved',reject函数将状态从'Pending'转为'rejected'。
基本语法,如下所示
new Promise((resolve,reject) => {
if(success){ //异步处理成功
resolve();
}else{
reject();
}
}).then(onFulfilled,onRejected);
创建一个Promise实例,如下所示
var promise = new Promise((resolve,reject) => {console.log('hehe');resolve('resolved')});
promise.then((val) => console.log(val))
console.log('current');
hehe
current
resolved
resolve函数与reject函数调用时可以传递参数,一般给reject函数传递Error的实例,用于指出抛出的错误,传给reject函数的参数可以是一般的数值,也可以是Promise的实例,这时该Promise的实例状态由参数Promise实例的状态决定,如下所示
var p1 = new Promise((resolve,reject) => {
setTimeout(()=>{console.log('1秒后的 p1');resolve(p2);},1000);
});
var p2 = new Promise((resolve,reject)=>{
setTimeout(()=>{console.log('2秒后的 p2');resolve('p2');},2000);
});
p1.then((val)=>console.log(val));
Promise { <state>: "pending" }
1秒后的 p1
2秒后的 p2
p2
如上所示,Promise是创建就立即执行,且then方法的回调函数将在当前脚本所有同步语句执行完执行,但是比定时器的队列优先级要高,如下所示
setTimeout(()=>console.log('settimeouting...'),0);
var promise = new Promise((resolve,reject) => {
console.log('promise constructing...');
reject(new Error('error'));
});
promise.then(null,(reason)=>console.log(reason));
promise constructing...
Promise { <state>: "pending" }
Error: error
堆栈跟踪:
promise<@debugger eval code:4:9
@debugger eval code:2:15
settimeouting...
Promise的原型方法then,该方法为promise实例添加状态改变时的回调函数,第一个参数是状态为resolved时的回调,第二个参数是状态为rejected的回调。如下所示
var p3 = new Promise((resolve,reject) => {
console.log('p3');
resolve('p3');
});
var p4 = new Promise((resolve,reject) => {
console.log('p4');
setTimeout(()=>resolve('p4'),1500);
});
p3.then(()=>p4).then((result) => console.log(result));//这里需要注意一点,如果then方法返回一个Promise实例,则下一个then回调需要等待该Promise实例的状态改变才会执行。
p3
p4
Promise { <state>: "pending" }
p4
Promise内部抛出的错误不会被捕获(Chrome浏览器除外),除非使用catch方法,如果在resolve之前抛出,则resolve不会执行,相反则相当于没有抛出错误,如下所示
var promise = new Promise((resolve,reject) => {
console.log('promise constructing...');
throw new Error('error');
resolve('haha');
});
promise.then((val)=>console.log(val));
promise constructing...
-------------------------------------------------------------
var promise = new Promise((resolve,reject) => {
console.log('promise constructing...');
resolve('haha');
throw new Error('error');
});
promise.then((val)=>console.log(val));
promise constructing...
haha
使用Promise的原型方法catch捕获错误,该方法其实是.then(null,reject)的别名,如下所示
var promise = new Promise((resolve,reject) => {
console.log('promise constructing...');
throw new Error('error');
resolve('haha');
});
promise.then((val)=>console.log(val)).catch((error)=>console.log(error));
promise constructing...
Promise { <state>: "pending" }
Error: error
堆栈跟踪:
promise<@debugger eval code:3:8
@debugger eval code:1:19
Promise的错误捕获可以使用then方法的第二个参数指定reject的回调函数,也可以使用Promise.prototype.catch方法捕获,但是一般推荐使用方法二,因为catch不仅能捕获到promise内部抛出的错误,then方法中的错误也能被捕获。但是在调用resolve方法之后,再抛出错误,不会被捕获,相当于没有抛出错误,如下所示
var promise = new Promise((resolve,reject) => {
throw new Error('promise error');
});
promise.then(null,(err)=>console.log(err));
Promise { <state>: "pending" }
Error: promise error
堆栈跟踪:
promise<@debugger eval code:2:9
@debugger eval code:1:19
---------------------------catch method-------------------
var promise = new Promise((resolve,reject) => {
reject(new Error('promise error'));
});
promise.catch((error)=>console.log(error));
Promise { <state>: "pending" }
Error: promise error
堆栈跟踪:
promise<@debugger eval code:2:9
@debugger eval code:1:19
---------------------------then方法中报错-------------------
var p5 = new Promise((resolve,reject) => {
resolve('hehe');
});
p5.then((val)=>val+x).catch((err)=>console.log(err));
Promise { <state>: "pending" }
ReferenceError: x is not defined
堆栈跟踪:
@debugger eval code:4:16
catch方法也是返回一个Promise,因此在catch后面还可以接着使用链式方法then,但这时then方法报错将不会被前面的catch捕获,如下所示
var p5 = new Promise((resolve,reject) => {
resolve('hehe');
});
p5.then((val)=>val+x).catch((err)=>console.log(err)).then((val)=>y+3);
Promise { <state>: "pending" }
ReferenceError: x is not defined
堆栈跟踪:
@debugger eval code:4:16
3.Promise.all
Promise.all方法可以将多个Promise实例[p1,p2,p3...]包装成一个Promise对象A,A的状态由p1,p2,p3...决定:如果p1,p2,p3...的状态都变为onfulfilled,A的状态才变为onfulfilled,且p1,p2,p3...的异步操作结果组成一个数组传给回调函数;但凡p1,p2,p3...中有一个状态变为了rejected,A的状态立即变为rejected,且第一个rejected的返回值会传给回调函数,如下所示
var p1 = new Promise((resolve,reject) => {
console.log('p1...');
setTimeout(()=>resolve('p1 resolved...'),1000);
});
var p2 = new Promise((resolve,reject) => {
console.log('p2...');
setTimeout(()=>resolve('p2 resolved...'),2000);
});
var p3 = new Promise((resolve,reject) => {
console.log('p3...');
setTimeout(()=>resolve('p3 resolved...'),3000);
});
Promise.all([p1,p2,p3]).then((args)=>{console.log('3S后的输出:');for(let v of args){console.log(v);}});
p1...
p2...
p3...
3S后的输出:
p1 resolved...
p2 resolved...
p3 resolved...
------------------------ 有一个Promise实例变为rejected ---------------
var p1 = new Promise((resolve,reject) => {
console.log('p1...');
setTimeout(()=>resolve('p1 resolved...'),1000);
});
var p2 = new Promise((resolve,reject) => {
console.log('p2...');
setTimeout(()=>resolve('p2 resolved...'),2000);
});
var p3 = new Promise((resolve,reject) => {
console.log('p3...');
setTimeout(()=>resolve('p3 resolved...'),3000);
});
var p4 = new Promise((resolve,reject) => {
console.log('p4...');
reject("p4 rejected...");
});
Promise.all([p1,p2,p3,p4]).then((args)=>console.log(args),(reason) => console.log(reason));
p1...
p2...
p3...
p4...
Promise { <state>: "pending" }
p4 rejected...
4.Promise.race
同Promise.all一样,该方法也是将多个Promise实例[p1,p2,p3...]包装成一个新的Promise实例B。"race"的字面意思就是竞争,所以[p1,p2,p3...]谁的状态先改变,B的状态立即改变一样的状态且第一个改变状态的promise实例的返回值传递给回调函数,如下所示
var p1 = new Promise((resolve,reject) => {
console.log('p1...');
setTimeout(()=>resolve('p1 resolved...'),1000);
});
var p2 = new Promise((resolve,reject) => {
console.log('p2...');
setTimeout(()=>resolve('p2 resolved...'),2000);
});
var p3 = new Promise((resolve,reject) => {
console.log('p3...');
setTimeout(()=>resolve('p3 resolved...'),3000);
});
Promise.race([p1,p2,p3]).then((val)=>console.log(val),(reason)=>console.log(reason));
p1...
p2...
p3...
Promise { <state>: "pending" }
p1 resolved...
5.Promise.resolve与Promise.reject
Promise.resolve是将给定的参数转换成一个Promise对象,如下所示
Promise.resolve(arg);//等同于new Promise((resolve)=>resolve(arg))
omise.resolve('resolve convert...').then((val)=>console.log(val));
Promise { <state>: "pending" }
resolve convert...
根据给定的参数类型不同,Promise.resolve有不同的动作:
A、参数为Promise实例,则直接返回该实例
B、参数为空,执行返回一个resolved状态的新Promise实例
C、参数为普通的数值或对象,则直接返回一个resolved状态的新Promise实例,如下所示
Promise.resolve({x:1}).then((val)=>console.log(val));
Promise { <state>: "pending" }
Object { x: 1 }
D、参数为thenable对象,既对象实现了then方法,此时返回一个新Promise实例并立即执行对象then方法,如下所示
var thenableObj = {
then(resolve,reject){
reject('test...');
}
};
Promise.resolve(thenableObj).then(null,(reason)=>console.log(reason));
Promise { <state>: "pending" }
test...
Promise.reject与Promise.resolve的用法一致,只是返回的Promise实例的状态为rejected,如下所示
Promise.reject('reject convert...').then(null,(reason) => console.log(reason));
Promise { <state>: "pending" }
reject convert...
6.给原生Promise对象扩展方法,如下所示
//一下两个函数来自raunyifeng博客
Promise.prototype.done = function (onFulfilled, onRejected) {
this.then(onFulfilled, onRejected)
.catch(function (reason) {
setTimeout(() => { throw reason }, 0);
});
};
该方法只要执行就可以捕获前面调用链中的错误
Promise.prototype.finally = function (callback) {
let P = this.constructor;
return this.then(
value => P.resolve(callback()).then(() => value),
reason => P.resolve(callback()).then(() => { throw reason })
);
};
该方法不管Promise的实例的状态是否改变都会执行回调函数
ES6 - Note5:Promise的更多相关文章
- es6从零学习(二):promise
es6从零学习(二):promise 一:promise的由来 某些情况下,回调嵌套很多时,代码就会非常繁琐,会给我们的编程带来很多的麻烦,这种情况俗称——回调地狱.由此,Promise的概念就由社区 ...
- ES6入门八:Promise异步编程与模拟实现源码
Promise的基本使用入门: ——实例化promise对象与注册回调 ——宏任务与微任务的执行顺序 ——then方法的链式调用与抛出错误(throw new Error) ——链式调用的返回值与传值 ...
- es6学习3:promise
promise含义: 所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果. 从语法上说,Promise 是一个对象,从它可以获取异步操作的消息.Pro ...
- ES6学习笔记五:Promise异步任务
一:Promise对象 Promise对象代表一个异步操作,有三种状态:Pending(进行中).Resolved(已完成,又称 Fulfilled)和Rejected(已失败). 二:创建与使用 v ...
- 深入理解 JavaScript 异步系列(3)—— ES6 中的 Promise
第一部分,Promise 加入 ES6 标准 原文地址 http://www.cnblogs.com/wangfupeng1988/p/6515855.html 未经作者允许不得转载! 从 jquer ...
- ES6中的Promise用法
Node的产生,大大推动了Javascript这门语言在服务端的发展,使得前端人员可以以很低的门槛转向后端开发. 当然,这并不代表迸发成了全栈.全栈的技能很集中,绝不仅仅是前端会写一些HTML和一些交 ...
- 深入浅出:promise的各种用法
https://mp.weixin.qq.com/s?__biz=MzAwNTAzMjcxNg==&mid=2651425195&idx=1&sn=eed6bea35323c7 ...
- 深入理解ES6里的promise
一.ES6 Promise是什么? 复杂的概念先不讲,我们先简单粗暴地把Promise用一下,有个直观感受.那么第一个问题来了,Promise是什么呢?是一个类?对象?数组?函数? 别猜了,直接打印出 ...
- ES6特性:(阮一峰老师)学习总结
ES6(阮一峰)学习总结 1.块级作用域的引入 在ES6之前,js只有全局作用域和函数作用域,ES6中let关键字为其引入了块级作用域. { var a = 5; let b = 6; } con ...
随机推荐
- 《HTTP权威指南》大块儿头
看到这样的一本书,胡乱翻开看看里面的内容,我觉得我又浮躁了.真厚啊!能学多少就学多少吧. 看看提要,这本书主要想讲的是HTTP和相关Web技术的.关于这方面的内容,知道的不多.
- mysql安装流程
一.配置MySQL数据库 1.解压绿色版mysql,如下图 二.安装服务 1.运行cmd(管理员版本,否则没有权限),如下图 2.运行命令mysqld –install安装服务,如下图: 如果不需要m ...
- Spring MVC篇二、使用JdbcTemplate进行数据库操作
上一篇只是一个简单的Spring MVC框架,接下来添加一些跟数据库的交互. 一.添加jdbc相关配置 在maven中添加相关依赖后,配置数据库访问参数及数据源.数据库参数使用配置文件,代码如下: ...
- Xamarin的不归路-生成安卓错误3
错误提示: 解决方案:升级jdk到8即可. 2016年9月1日14:50
- DNS域名服务器
DNS是用来解析域名的,IP就相当于地址一样,不知道IP就没法访问指定网络.要上PC6下载站,输入www.pc6.com, 得先问问DNS大哥www.pc6.com在哪,然后Dns告诉你后,就上去了w ...
- css 清除浮动 clear
.clearfix{ zoom:1;/*对于老版本的IE进行兼容的设置*/ } .clearfix:after{ content:""; display:block; visibi ...
- 三、jquery操作DOM
DOM(Document Object Model, 文档对象模型)为文档提供了一种结构化的表示方法,通过该方法可以改变文档的内容和展示形式.在实际运用中,DOM更像是桥梁,通过它可以实现跨平台.跨语 ...
- 移动端图片上传base64编码
$base64 = "/9j/4AAQSkZJRgABAQEAkACQAAD/4QCMRXhpZgAATU0AKgAAAAgABQESAAMAAAABAAEAAAEaAAUAAAABAAAA ...
- UML类图的6大关系
<小酌重构系列>已经完成了大约1/3了,在这些文章中,我使用了一些简单的类图来描述重构策略.在之后的文章中,我可能会借助稍微复杂一些的UML类图来介绍.但是在此之前,我觉得有必要先介绍一下 ...
- 记录Office Add-in开发经验
原创文章转载请注明出处:@协思, http://zeeman.cnblogs.com 得益于微软系强大的共通能力和Visual Studio的开发支持,做Office插件不是什么难事.一点经验记录如下 ...