还是要强调一下,我的ES6学习主要参考的是阮一峰大神的书,作笔记的目的,就是把对于我来说比较重要或者易错的点整理出来方便自己再次学习有所偏重,真的对这些不懂的请看原文:http://es6.ruanyifeng.com/#docs/promise阮一峰大神写得真的很好哎
先简单介绍一下Promise对象
Promise对象的特点:
promise的长处和缺点
长处:
Promise对象的用法
Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve和reject。它们是两个函数,由JavaScript引擎提供,不用自己部署
resolve函数的作用是,将Promise对象的状态从pending变为resolved,在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;reject函数的作用,将Promise对象的状态从pending变为rejected,在异步操作失败的时候调用。并将异步操作报出的错误,作为参数传递出去。
Promise实例生成以后,可以用then方法分别指定resolved状态和rejected状态的回调函数。
.then()方法接收两个回调函数作为参数,第一个回调函数是Promise对象的状态变为resolved时调用,第二个回调函数是Promise对象的状态变为rejected时调用。其中第二个函数是可选的,不一定要提供。这两个函数都接收Promise对象传出的值作为参数
Promise状态发生改变,会触发.then()里面的响应函数,.then()根据其最终状态,选择特定的状态响应函数执行,状态响应函数,可以返回新的Promise或其它值,如果返回新的Promise,那么下一级.then()会在新的Promise状态改变之后执行,如果返回其它任何值,则会立刻执行下一级.then()。没有明确返回值,就相当于return undefined,仍然不会影响Promise执行,即使在里面return false也不会影响下一步,false可以直接传到下一步。
嗯、看下面的例子吧
console.log('here we go');
new Promise(resolve =>{
setTimeout(()=>{
resolve('hello');
},2000);
})
.then(value=>{
console.log(value);
return new Promise(
resolve=>{
setTimeout(
()=>{
resolve('leo')
},2000);
});
}).then(value=>{
console.log(value+' world');
})
再看个例子
console.log("donna");
let promise = new Promise(resolve=>{
setTimeout(()=>{
console.log("hello leo");
resolve('jon is good');
},1000);
});
setTimeout(()=>{
promise.then(value=>{
console.log(value);
});
},3000);
嗯,原理和上一个差不多,只不过,这个例子中.then()没有直接链接在Promise实例后面,这种写法也是可以的。这个结果是,先打印donna,然后hello leo 最后打印jon is good
再看一个容易掉坑的例子
console.log('here we go');
new Promise(resolve=>{
setTimeout(()=>{
resolve('hello');
},2000);
}).then(value=>{
console.log(value+ ' world');
(function (){
return new Promise(resolve=>{
setTimeout(()=>{
console.log("donna");
resolve("bangbang");
},4000)
});
}());
return false;
}).then(value=>{
setTimeout(()=>{
console.log(value+ " bingbing");
},3000)
})
先猜猜结果,看你会不会掉坑
嗯,宣布结果 打印的先后顺序为 here we go 、hello world 、false bingbign、donna
跟你想象的一样吗?提醒一下,第一个then方法里面返回的Promise实例是在立即执行函数里面的,不是这个then方法的返回值,它的返回值是false,所以它不会等里面的定时器执行完,就跳到了下一个then方法中执行(记得value是上一个then方法返回的false),执行完之后,才去执行上面的定时器中的内容
Promise.prototype.catch方法是.then(null,rejection)的别名。用于指定错误时的回调函数
如果异步操作抛出错误,状态就会变为rejected,就会调用catch方法指定的回调函数,处理这个错误,另外,then方法指定的回调函数,如果抛出错误,也会被catch方法捕获。
p.then((val) => console.log('fulfilled:', val))
.catch((err) => console.log('rejected', err));
// 等同于
p.then((val) => console.log('fulfilled:', val))
.then(null, (err) => console.log("rejected:", err));
嗯,再看一个例子
const promise = new Promise(function(resolve, reject) {
try {
throw new Error('test');
} catch(e) {
reject(e);
}
});
promise.catch(function(error) {
console.log(error);
});
// 写法二
const promise = new Promise(function(resolve, reject) {
reject(new Error('test'));
});
promise.catch(function(error) {
console.log(error);
});
const promise = new Promise(function(resolve, reject) {
throw new Error('test');
});
promise.catch(function(error) {
console.log(error);
});
// Error: test
这三种方法是等价的,从上面我们也可以发现,reject方法的作用等同于抛出错误
注意:如果,promise的状态已经成功,再抛出错误是无用的,因为Promise的状态一旦确定就无法改变
一般来说,不要在then方法里面定义reject状态的回调函数(即then的第二个参数),总是使用catch方法。跟传统的try/catch代码块不同的是,如果没有使用catch方法指定错误处理的回调函数,Promise对象抛出的错误不会传递到外层代码,即不会有任何反应。
所以总是建议,Promise对象后面要跟catch方法,这样可以处理Promise内部发生的错误。catch方法返回的还是一个Promise对象,因此后面还可以接着调用then方法。Promise对象的错误具有“冒泡”性质,会一直向后传递,直到捕获为止。也就是说,错误总是会被下一个catch语句捕获,如果没有报错则会跳过catch方法,接着运行后面的then方法指定的回调函数。
Promise.resolve()方法:有时需要将现有对象转为Promise对象,Promise.resolve方法就起到这个作用
Promise.resolve等价于new Promise(resolve=>resolve('foo'));
Promise.resolve方法的参数分四种情况。
//使用Promise.resolve方法
let thenable = {
then:function(resolve){
resolve("donna");
}
}
Promise.resolve(thenable).then(value=>{
console.log(value);//donna
});
//上面的方法类似下面的这样
new Promise(resolve=>{
resolve("donna");
}).then(value=>{
console.log(value);
})
如果参数是一个原始值,或者是一个不具有then方法的对象,则Promise.resolve方法返回一个新的Promise对象,状态为resolved
let obj= {
str:function(){
console.log(123);
}
}
Promise.resolve(obj).then(value=>{
console.log(value);//{str:f}
});
上面的代码生成一个新的Promise对象的实例,由于对象obj不是thenable对象,返回Promise实例的状态从一一生成就是resolved,所以回调函数会立即执行,Promise.resolve方法的参数会同时传给回调函数
Promise.resolve方法允许调用时不带参数,直接返回一个resolved状态的Promise对象。所以如果希望得到一个Promise对象,比较方便的方法就是直接调用Promise.resolve方法
注意:立即resolve的Promise对象,实在本轮“事件循环”的结束时,而不是在下一轮“事件循环”的开始时
setTimeout(()=>{
console.log("weiwei");
},0);
let thenable = {
str:function(){
console.log(123);
}
}
Promise.resolve(thenable).then(value=>{
console.log(value);//{str:f}
});
console.log("hongbao");//hongbao {str:f} weiwei
上面的代码中,setTimerout(fn,0),在下一轮“事件循环”开始时执行,Promise.resoolve()在本轮“事件循环”结束时执行,console.log('hongbao')则是立即执行,因此最先输出。
Promise.reject(reason)方法也会返回一个新的Promise实例,该实例的状态为rejected
注意:Promise.reject()方法的参数会原封不动传给后续方法的参数,这一点与Promise.resolve方法不一致
const thenable = {
then(resolve, reject) {
reject('出错了');
}
};
Promise.reject(thenable)
.catch(e => {
console.log(e === thenable)
})
// true
上面代码,Promise.reject方法的参数是一个thenable对象,执行以后,后面的catch方法的参数不是reject抛出的“出错了”这个字符串,而是thenable
Promise.all():该方法用于将多个Promise实例,包装成一个新的Promise实例
Promise.all对象接收一个数组作为参数,并且数组的成员都是Promise实例,如果不是,就会先调用上面谈到的Promise.resolve方法将参数转为Promise实例,再进一步处理。(注意:Promise.all的参数可以不是数组,但必须具有Iterator接口,且返回的每个成员都是Promise实例)返回值是一个新的Promise实例,传递给该对象的回调函数
当所有的Promise都完成,该Promise完成,返回值是全部值的数组,有任何一个失败,该Promise失败,返回值是第一个失败的子Promise的结果,也会传递给该对象的回调函数。
Promise.race()方法类似Promise.all()方法,区别在于它有任意一个完成就算成功