Promise介绍
Promise是异步编程的一种解决方案(ES7开始正式上线),用于处理回调地狱的问题。
下面是一个典型的回调地狱,
doSomething(function(result) {
doSomethingElse(result, function(newResult) {
doThirdThing(newResult, function(finalResult) {
console.log('得到最终结果: ' + finalResult);
}, failureCallback);
}, failureCallback);
}, failureCallback);
我们把他改成promise试试
doSomething().then(function(result) {
return doSomethingElse(result);
})
.then(function(newResult) {
return doThirdThing(newResult);
})
.then(function(finalResult) {
console.log('得到最终结果: ' + finalResult);
})
.catch(failureCallback);
代码可读性非常强
Promise对象的创建
下面我们列举一个Promise的基本形态
const p=new Promise((resolve,reject)=>{
})
promise
接收一个函数,这个函数的两个参数resolve
和reject
,其作用是让函数返回结果正确还是错误。
现在我们创建一个Promise对象
//p是一个promise对象
const p=new Promise((resolve,reject)=>{
//进行处理
let data=Math.random()*5
if(data>2){
resolve('成功')
}else{
reject('失败')
}
})
创建好了又要怎么使用呢?
Promise对象的使用
promise对象有3个常用的方法
- then()
- catch()
- finally()
then()
then
是实例状态发生改变时的回调函数,第一个参数是resolved
状态的回调函数,第二个参数是rejected
状态的回调函数
如果上一个promise返回的是resolve
(成功)的结果,那么就回触发resolved的函数,或者触发reject
(失败)的函数。
p.then((resolve)=>{
console.log(resolve) //打印:成功
},(reject)=>{
console.log(reject) //打印:失败
})
then
方法返回的是一个新的Promise
实例,也就是promise
能链式书写的原因,下面举个例子
p1.then((req)=>{
console.log(req)
return p2
})
.then(req => {
console.log(req)
})
catch()
catch()
方法是.then(null, rejection)
或.then(undefined, rejection)
的别名,用于指定发生错误时的回调函数
Promise
对象的错误具有“冒泡”性质,会一直向后传递,直到被捕获为止.
p.then(req=>{
console.log(req);
}).catch(e=>{
console.log('catch',e);
})
//输出 catch 失败
如果错误在之前被捕获,则不会进入catch
p.then(req=>{
console.log(req);
},res =>{
console.log(res);
}).catch(e=>{
console.log('catch',e);
})
//输出 失败
大部分情况下,catch用于代替then的第二个参数。
此时补充一点,promise内部抛出的错误不会传递到外部,即不会退出进程
try{
p.then(req=>{
console.log(req);
console.log( NoDefinedValue +1)
}).catch(e=>{
console.log('catch捕获',e);
})
}catch(e){
console.error('外层捕获',e)
}
/*
控制台输出:
catch捕获 ReferenceError: NoDefinedValue is not defined
*/
finally()
无论请求是否成功,finally都会执行
p.then(req=>{
console.log(req);
}).catch(e=>{
console.log('catch捕获',e);
}).finally(()=>{
//没有参数传递
console.log('finally')
})
Promise的构造函数方法
all()
Promise.all()
方法用于将多个 Promise
实例,包装成一个新的 Promise
实例
const p = Promise.all([p1, p2, p3]);
接受一个数组(迭代对象)作为参数,数组成员都应为Promise
实例
实例p
的状态由p1
、p2
、p3
决定,分为两种:
- 只有3个实例全部成功,p的状态才为成功,并返回成功的数组
- 只要3个使用有一个失败,p的状态就为失败,并且将第一个失败的值返回
注意,如果作为参数的 Promise
实例,自己定义了catch
方法,那么它一旦被rejected
,并不会触发Promise.all()
的catch
方法
成功案例:
let s1=new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve('s1');
},1000);
});
let s2=new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve('s2')
},1000);
});
let s3=new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve('s3');
},1000);
});
let s=await Promise.all([s1,s2,s3]).then(result => {
console.log('s成功',result)
},(res)=>{
console.log('s失败',res)
})
//打印 s成功 ['s1', 's2', 's3']
失败案例:
let s1=new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve('s1');
},1000);
});
let s2=new Promise((resolve,reject)=>{
setTimeout(()=>{
reject('s2')
},1500);
});
let s3=new Promise((resolve,reject)=>{
setTimeout(()=>{
reject('s3');
},1000);
});
let s=await Promise.all([s1,s2,s3]).then(result => {
console.log('s成功',result)
},(res)=>{
console.log('s失败',res)
})
//打印 s失败 s3
如果p2
没有catch
,那么会被Promise.all().catch()
捕获,否则则在p2中处理
race()
Promise.race()
方法同样是将多个 Promise 实例,包装成一个新的 Promise 实例
const p = Promise.race([p1, p2, p3]);
只要p1
、p2
、p3
之中有一个实例率先改变状态,p
的状态就跟着改变
率先改变的 Promise 实例的返回值则传递给p
的回调函数
let s1=new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve('s1');
},1000);
});
let s2=new Promise((resolve,reject)=>{
setTimeout(()=>{
reject('s2')
},1500);
});
let s3=new Promise((resolve,reject)=>{
setTimeout(()=>{
reject('s3');
},1100);
});
let s=await Promise.all([s1,s2,s3]).then(result => {
console.log('s成功',result)
},(res)=>{
console.log('s失败',res)
})
//打印 s成功 s1
allSettled()
Promise.allSettled()
方法接受一组 Promise 实例作为参数,包装成一个新的 Promise 实例
只有等到所有这些参数实例都返回结果,不管是成功
还是失败
,包装实例才会结束
let s1=new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve('s1');
},1000);
});
let s2=new Promise((resolve,reject)=>{
setTimeout(()=>{
reject('s2')
},1500);
});
let s3=new Promise((resolve,reject)=>{
setTimeout(()=>{
reject('s3');
},1100);
});
let s=await Promise.all([s1,s2,s3]).then(result => {
//无论s1,s2,s3结果如何,都会来到这里
console.log('s成功',result)
})
resolve
将现有对象转为 Promise
对象
Promise.resolve('foo')
// 等价于
new Promise(resolve => resolve('foo'))
参数可以分成四种情况,分别如下:
- 参数是一个 Promise 实例,
promise.resolve
将不做任何修改、原封不动地返回这个实例 - 参数是一个
thenable
对象,promise.resolve
会将这个对象转为Promise
对象,然后就立即执行thenable
对象的then()
方法 - 参数不是具有
then()
方法的对象,或根本就不是对象,Promise.resolve()
会返回一个新的 Promise 对象,状态为resolved
- 没有参数时,直接返回一个
resolved
状态的 Promise 对象
reject
该方法与resolve
类似,只是状态为reject
,不做展示。
Q.E.D.