书籍参考:《ECMAScript 6入门》 作者:阮一峰
文档参考:MDN
概念
Promise最初在社区提出的一个异步解决的方案,最后ES6将它加入了正式的标准,并规定了统一的写法。
在使用Promise之前,你需要注意下面几个点:
1.Promise有三个状态:Pending(进行中)
、Resolved(已完成)
、Rejected(已失败)
,这三个状态我们无法去改变,并且在一个Promise中只有两个可能,一种是从Pending
到Resolved
,另一种是Pending
到Rejected
。当结果发生后,这个状态就凝固了,也就是说我们无法去改变Promise对象的任何状态,如果再次调用这个Promise对象,返回的将是凝固状态的结果。
2.Promise在执行的过程中无法取消,并且我们也无法知道它执行到哪一步,我们只能知道返回的是已完成还是已失败。
3.Promise实例创建后会立即执行
下面的代码部署了一个Promise对象异步加载图片的例子,可以看到用Promise对象来编写异步代码是非常的清晰。
var imgs = new Promise((resolve, reject) => {
let img = new Image();
img.src = 'http://xxx.com/img.jpg';
img.onload = function(){
resolve('加载成功');
}
img.onerror = function(){
reject('加载失败');
}
});
在部署了Promise对象后,我们可以通过Promise的实例来调用then()
方法,then()
方法接受两个函数,这两个函数分别指定resolved
和rejected
状态返回的回调函数。第二个函数可以不指定,也就是说不返回错误,只得到完成的结果。
var imgs = new Promise((resolve, reject) => {
let img = new Image();
img.src = 'http://xxx.com/img.jpg';
img.onload = function(){
resolve('加载成功');
}
img.onerror = function(){
reject('加载失败');
}
});
imgs.then(function(value){
console.log(value);
}, function(error){
console.log(error);
});
Promise可以用于多个异步操作,下面的代码是判断img是否加载成功,如果加载成功就将img添加进div容器中。
var imgs = new Promise((resolve, reject) => {
let img = new Image();
img.src = 'http://xxx.com/img.jpg';
img.onload = function(){
resolve({
img,
status: '加载成功'
});
}
img.onerror = function(){
reject('加载失败');
}
});
var loadImg = new Promise((resolve, reject) => {
let imgDiv = document.getElementById('imgdiv');
imgs.then(function(value){
imgDiv.innerHtml(value.img);
}, function(error){
console.log(error);
});
});
then()、catch()
Promise对象原型上定义了两个方法,分别为then()
和catch()
,then()
和上面的一样,接受两个函数,可以不需要第二个函数,而catch()
函数相当于then(null, reject)
的别名。我们把上面的代码来修改,下面的代码同样能到达相同的效果,但是看上去更加简洁。
var imgs = new Promise((resolve, reject) => {
let img = new Image();
img.src = 'http://xxx.com/img.jpg';
img.onload = function(){
resolve('加载成功');
}
img.onerror = function(){
reject('加载失败');
}
});
imgs.then(function(value){
console.log(value);
});
imgs.catch(function(error){
console.log(error);
});
链式写法
由于Promise对象返回的是执行过后的一个新Promise对象,而then
方法主要是捕获返回的对象里面PromiseStatus
属性的值为'resolved',而catch
方法主要是捕获返回的对象里面PromiseStatus
属性的值为'rejected',而每次then或者catch都会返回一个新的Promise对象,这个新的Promise对象里的值就是从上一个Promise对象中获取的。从这些说明中,我们可以使用链式写法简洁明了的写出异步编程。
var imgs = new Promise((resolve, reject) => {
let img = new Image();
img.src = 'http://xxx.com/img.jpg';
img.onload = function(){
resolve('加载成功');
}
img.onerror = function(){
reject('加载失败');
}
});
imgs
.then(value => console.log(value))
.catch(error => console.log(error));
Promise.resolve()、Promise.rejcet()
Promise.resolve()
方法接受一个参数,用于将参数转换为一个Promise对象。如果参数是一个基本类型值,那么将直接返回状态为resolved
和值为参数的Promise对象
Promise.resolve($.ajax('http://www.youdao.com/'));
Promise.resolve(2);
Promise.rejcet()
方法和Promise.resolve()
的用法一致,但返回的是一个已失败的Promise对象。
Promise.all()
Promise对象上有一个all方法,用于将一个数组或者具备Iterator接口的数据结构组合成一个多Promise对象实例的Promise对象。如果状态都是已完成,就会返回resolved
状态,如果其中有一个Promise实例返回rejected
。如果数组中的成员不是Promise对象,那么就调用Promise.resolve()
方法返回一个有效的Promise对象。Promise.all()
方法非常适合多个Promise对象控制,也就是说我需要10个异步调用都执行成功,那么可以用这个方法来控制。
比如下面,我需要两个图片都加载成功了才进行下一步操作。
var imgs1 = new Promise((resolve, reject) => {
/* Code */
});
var imgs2 = new Promise((resolve, reject) => {
/* Code */
});
Promise.all([imgs1, imgs2])
.then(value => console.log(value))
.catch(error => console.log(error));
Promise.race()
Promise.race()
方法的使用和Promise.all()
一致,但是行为不一致,Promise.race()
方法接受的多个Promise对象中,只要有一个Promise对象的状态率先改变,那么Promise.race()
的状态就为率先改变的Promise对象返回的状态。
文完
《es6-promise》留言数:0