ES5及以下,要实现复杂的异步编程,需要大量运用回调函数,每一个回调函数(JS引擎把它当作一个代码块)依次进入单线程(JS)任务队伍依次执行,而每个回调函数中的执行正确与否无法及时判断,当中信息反馈及显示都只会在最外层函数执行完毕后才反馈给你,让你只能猜测或分析找问题,这将造成大量无法理解的情况出现。对于复杂嵌套回调问题,你将不得不花费大量精力去跟踪各个回调函数运行及清理相互影响。
ES6新标准引入Promise对上述问题进行解决,它的核心思想,是将上一次函数执行返回一个Promise对象,明确指示代码是否成功执行,则你可以基于此成功与否判断,以链式编程方式将复杂嵌套回调函数转换为简单流程化式的形式完成目标任务。
一、Promise的基本用法
每个Promise都会经历一个短暂的生命周期,当处于进行中时标记为pending状态,一旦异步操作结束,Promise标记为settled状态,如果操作出现错误或未完成,标记为unsettle状态。其内部属性[[PromiseState]],分别对应这三种状态,分别是”pending”、“fulfilled”和”rejected”。其内部会自动调用then()方法响应fulfilled成功状态,catch()方法响应rejected。
Then()方法调用时,与异步操作相关的附加数据都会传递给这个完成响应函数。Catch()调用时,所有与失败状态相关的附加数据都会传递给这个拒绝响应函数。
1.基本用法
Promise构造函数可以创建Promise,构造函数接受两个参数,分别是resolve()函数与reject()函数,执行成功完成时调用resolve()函数,失败时则调用reject()函数。
Promise.resolve方法是将一个对象转换成Promise对象,如果入参是一个Promise对象,则直接返回该对象;如果入参是一个thenale对象(表示该对象已经调用了then方法),则返回的是一个新的Promise对象;如果无任何参数,则返回一个fulfilled状态的Promise对象。
Promise.reject方法可以快速返回被rejected的Promise对象。该方法接收一个参数作为入参,这个参数将成来被rejected对象的reason属性,传给rejected回调函数。
let promise1=new Promise(function(resolve,reject){//模拟函数成功执行
resolve("成功");
});
promise1.then(function(contents){
console.log(contents);//输出---成功
});
let promise2=new Promise(function(resolve,reject){//模拟函数拒绝执行
reject(new Error("拒绝"));
});
promise2.catch(function(err){
console.log(err);//输出---Error:拒绝
});
2.具体运用实例
function readNumber(num){//定义Promise实例函数
return new Promise(function(resolve,reject){
if(num<0){
reject("输入的数字小于0,拒绝兑换");
return;
}
resolve("输入的数字大于0,执行兑换");
});
}
let promise1=readNumber(45);//执行成功输入
promise1.then(function(contents){
console.log(contents);//输出结果:输入的数字大于0,执行兑换
});
promise1.catch(function(err){
console.log(err);//此函数不会被调用,故无此输出
});
let promise2=readNumber(-6);//执行失败输入
promise2.then(function(contents){
console.log(contents);//此函数不会被调用,故无此输出
});
promise2.catch(function(err){
console.log(err);//输入的数字小于0,拒绝兑换
});
二、Promise的串联(链式)用法
Promise每次调用then()方法和catch()方法时,实际上创建了另一个Promise,只有当第一个Promise完成或被拒绝时,第二个才会被解决。因此,就给解决复杂问题链式化提供了条件,而不是用复杂或嵌套式回调函数去解决。其写法如下:
Let p1=new Promise(function(resolve,reject){ });
P1.then(function(){ }).then(funciton(){ })…
以上述实例为具体实现,如下:
function readNumber(num){//定义Promise实例函数
return new Promise(function(resolve,reject){
if(num<0){
reject("输入的数字小于0,拒绝兑换");
return;
}
resolve("输入的数字大于0,执行兑换");
});
}
let promise1=readNumber(45);//执行成功输入
promise1.then(function(contents){
console.log(contents);//输出结果:输入的数字大于0,执行兑换
}).then(function(){
console.log("由于有兑换劵,就可以进入购买了");//输出结果:由于有兑换劵,就可以进入购买了
});
let promise2=readNumber(-8);//执行失败输入
promise2.then(function(contents){
console.log(contents);//输出结果:输入的数字大于0,执行兑换
}).then(function(){
console.log("由于有兑换劵,就可以进入购买了");//无输出结果:由于readeNumber输入的是-8,第一个then不满足,为拒绝状态,因而第二个then没有调用,而第三个then是基于第二个then呈错误状态的,所有第三个then被执行
}).catch(function(){
console.log("由于没有有兑换劵,无法进入");//输出结果:由于没有有兑换劵,无法进入
})
三、多Promise响应用法
如果你想通过多个Promise来决定下一步的操作,则可以使用ES6提供的Promise.all()和Promise.race()两个方法来监听多个Promise。
1.Promise.all()方法
Promise.all()方法只接受一个参数并返回一个Promise,该参数是一个含有多个受监视Promise的可迭代对象(例如,一个数组),只有当可迭代对象中所的Promise都被解决后返回的Promise才会被解决,只有当可迭代对象中所有Promise都被完成返回后的Promise才会被完成。
let p1=new Promise(function(resolve,reject){
resolve(42);
});
let p2=new Promise(function(resolve,reject){
resolve(43);
});
let p3=new Promise(function(resolve,reject){
resolve(44);
});
let p4=Promise.all([p1,p2,p3]);
p4.then(function(value){ //因为P4呈完成状态,所以没有调用catch,而是调用的then方法
console.log(Array.isArray(value));//输出结果:true
console.log(value[0]);//输出结果:42
console.log(value[1]);//输出结果:43
console.log(value[2]);//输出结果:44
})
上述例中,只有当迭代中所有都完成,P4才呈完成状态;反之,只要有一个被拒绝,那么返回的Promise没等其他后面Promise完成就立即呈拒绝状态。如下:
let p1=new Promise(function(resolve,reject){
resolve(42);
});
let p2=new Promise(function(resolve,reject){
reject(43);
});
let p3=new Promise(function(resolve,reject){
resolve(44);
});
let p4=Promise.all([p1,p2,p3]);
p4.catch(function(value){//因为P4呈拒绝状态,所以没有调用then,而是调用的catch方法
console.log(Array.isArray(value));//输出结果:false
console.log(value);//输出结果:43
});
2.Promise.race()方法
Promise.race()方法也监听多个Promise,与Promise.all方法不一样,它只要有一相Promise被解决则立即返回呈解决状态,无须等到所有的Promise都被解决。
let p1=new Promise(function(resolve,reject){
resolve(42);
});
let p2=new Promise(function(resolve,reject){
resolve(43);
});
let p3=new Promise(function(resolve,reject){
resolve(44);
});
let p4=Promise.race([p1,p2,p3]);
p4.then(function(value){//只要p1呈完成状态,就立即返回呈完成状态,其他后面Promise则被忽略
console.log(Array.isArray(value));//输出结果:false
console.log(value);//输出结果:42
});
实际上,传给Promise.race()方法的Promise会进行竞选,以决出哪一个先被解决完成,就选哪一个,并以最先解决状态而呈相同状态,其他的则被忽略。
let p1=new Promise(function(resolve,reject){
setTimeout(function(){resolve(42);},200);
});
let p2=new Promise(function(resolve,reject){
resolve(43);
});
let p3=new Promise(function(resolve,reject){
resolve(44);
});
let p4=Promise.race([p1,p2,p3]);
p4.then(function(value){//由于p1被延迟执行,所以p2最先呈完成状态,故最后输出为p2状态
console.log(Array.isArray(value));//输出结果:false
console.log(value);//输出结果:43
});