Promise 是ES6新增的对于异步编程的一种解决方案,比普通的回调函数解决异步问题功能更强大
补充知识点:回调函数
下例中的callback函数就称为a函数的回调函数
function a(fn) {
fn(); //a回调一下fn
}
function callback() {
console.log('1111');
}
a(callback); //1111
const pro1 = new Promise(function (res,rej) {
setTimeout(function(){
console.log('pro1包含的异步操作');
},1000)
});
pending:进行中
fulfilled:已完成--成功
rejected:已失败--失败
特性:promise的状态只能从pending--->fullfiled 或者 从pending--->rejected,promise对象的状态一旦改变,就不会发生第二次改变
const pro1 = new Promise(function (res,rej) {
setTimeout(function(){
console.log('pro1包含的异步操作');
//res('pro1成功后的promise结果') //将异步结果状态从pending(进行中)转为fulfilled(已完成/成功的)
rej('pro1失败后的promise结果') //将异步结果状态从pending(进行中)转为rejected(已失败/失败的)
//这两个实参是函数,只能运行一个,不可能说既成功又失败
},1000)
});
我们可以在new Promise的回调函数中定义任意的异步操作,至于状态最终结果是成功fullfiled 还是失败rejecte,都是由我们自己决定的。
那外面如何捕获promise的结果呢?需要用到promise原型链中的then方法
promise对象一旦产生,就会立马执行,有时候我们需要的是在调用它的时候才执行,所以可以采用封装函数来解决这个问题。
function getPromise() {
return new Promise ((res,rej)=>{
setTimeout(function(){
res('返回成功结果')
},1000)
})
}
const pro1 = getPromise();
console.log(pro1); //'返回成功结果'
//下次需要使用该promise对象时,又在声明调用一次
const pro2 = getPromise();
1. .then( )方法
返回结果为一个新的promise对象
pro2是由Promise创建出来的,所以pro2.__proto__ == Promise.prototype。Promise.prototype里面有then方法,那么pro2就可以直接用then方法。
new Promise(function (参数1,参数2) 一些异步操作)
这个是声明promise对象的固定搭配,其中参数1和参数2是固定的,是函数。参数1表示异步操作成功的函数,参数2表示异步操作失败的函数。
const pro2 = new Promise(function (res,rej)
setTimeout(function(){
console.log('pro1包含的异步操作');
//res('异步执行完成的结果')
//res()调用,得到promise对象产生的结果(字符串'异步执行完的结果') .then方法就会立马执行里面的第一个函数,并且将res参数传给第一个函数
rej('异步执行失败的结果')
//将res参数:结果(字符串'异步执行失败的结果')传给.then方法的第二个函数
},1000)
})
pro2.then(function(rig){
console.log(rig); //成功,就打印rig实参的内容
},function (err) {
console.log(err); //失败,就打印err实参的内容
});
注意:在手动调用res/rej函数可以把promise状态置为成功/失败,需要满足代码逻辑不能出错,下面展示三种代码逻辑出错的情况
情况一:不符合逻辑的代码出现在res/rej函数之前,程序卡住,无法设置promise的结果
const pro3 = new Promise(function (res,rej) {
setTimeout(function(){
console.log('pro1包含的异步操作');
console.log(x);
res('异步执行完成的结果')
},1000)
})
//结果打印'pro1包含的异步操作',然后报错(is not defined)
//后面的res会卡住,不能设置promise的结果
情况二:
const pro3 = new Promise(function (res,rej) {
setTimeout(function(){
console.log('pro1包含的异步操作');
var x = '异步执行完成的结果';
res(x);
},1000)
})
//不能打印'异步执行完成的结果',卡住,无法将promise结果置为成功
情况三:先设置promise的结果,再出现不符合逻辑的代码,并不影响promise的结果。promise的结果一旦发生改变,就不会再更改。
const pro3 = new Promise(function (res,rej) {
setTimeout(function(){
console.log('pro1包含的异步操作');
res('异步执行完成的结果');
console.log(x);
},1000)
})
console.log(pro3); 后面不会卡住 已经成功了
//[[Prototype]]: Promise
//[[PromiseState]]: "fulfilled"
//[[PromiseResult]]: "异步执行完成的结果"
2. catch方法以及链式调用
.then( ).catch( )
.catch( )是为了替代.then中的第二个回调函数,用来捕获promise对象的错误,它可以捕获它之前的错误。下例中pro3调用了r(),就触发了pro3.then(),将'异步成功'作为参数传给.then()并打印,接下来.then()里面代码出现了逻辑错误(console.log(x)),因此就触发了.catch(),将'x is not defined'作为参数传给.catch()并打印。
const pro3 = new Promise((r,j)=>{
r('异步成功');
// j('异步失败')
})
pro3.then(res=>{
console.log(res); //异步成功
console.log(x);
}).catch(err=>{
console.log(err); //ReferenceError: x is not defined
})
总结:new Promise( )中的操作代码逻辑没问题,直接走下一个.then里面去,并且会把return的结果作为下一个.then的参数;如果出现问题,就是走到.catch,将return的结果作为.catch的参数。
const pro4 = new Promise((r,j)=>{
r('异步成功'); //传给res1作为参数
//j('异步失败')
})
pro4.then(res1=>{
console.log(res1); //异步成功
return 'res1成功' //传给res2作为参数
}).then(res2=>{
console.log(res2); //res1成功
}).catch(err=>{
console.log(err); //没有错误可以捕捉,因此不打印
})
链式调用的练习题
const pro3 = new Promise((resolve, reject) => {
resolve('one'); //promise结果为成功,将one传入.then()的实参中
});
pro3
.then((val) => {
console.log(val); // 'one'
return x; //出现错误,接下来走.catch(),将'x is not defined'传给.catch
})
.then((val) => {
console.log(val);
})
.catch((err) => {
console.log(err); // 'x is not defined'
console.log(typeof err); // object
return err; //返回'x is not defined'以供接一下来的.then使用
})
.then((val) => {
console.log(val); // 'x is not defined'
})
.catch((err) => {
console.log(err);
})
3. .finally ()方法
Promise.prototype.finally。不管promise对象的状态是成功还是失败,都一定会触发finally里面的方法。它存在的意义是,无论成功还是失败,都要进行的操作(比如:无论请求失败还是成功,都要让网页的loading停下来)
1. Promise.all
将几个promise对象放在一个数组里面,返回一个新的promise对象,同样也可以使用前面的方法。只有当数组中所有的promise对象都成功时,它才会走到.then里面表示成功;一旦有一个promise对象失败/出错,那结果就走到.catch方法。
2. Promise.resolve(参数)
将现有的对象转为promise对象:
a. 如果现有对象本身就是promise对象,则该方法直接返回原promise对象(引用地址也一样)
b.参数是一个thenable对象,立马将该对象转为promise对象,并且立马执行它自己的then方法(不是promise实例对象的then方法,是thenable对象内的一个方法名而已,但不能更改这个方法名),将这个promise对象变为成功/失败状态
解释thenable对象:这个对象里面有如下所示的then方法的对象
const obj = {
then:function(res,rej){
res('成功了');
// rej('失败了');
}
}
const pro6 = Promise.resolve(obj);
pro6.then(r=>{
console.log(r); //成功了,说明obj转化为promise对象时就是pro6
}).catch(e=>{
console.log(e);
})
c. 参数不是thenable对象 或 不是对象,则返回一个已经resolve(成功)状态的promise对象,并且该promise对象的结果为传入的参数
d.参数为空,则返回一个已经resolve(成功)状态的promise对象,结果为undefined
2. Promise.reject()
返回一个已经rejected(失败)状态的promise对象。传入的参数直接被当成是失败的结果
,用.catch来捕捉这个错误