文章目录
Promise
一、什么是Promise
概述:Promise是处理异步问题的一种方式,之前都是用回调函数,如setTimeout( ( )=>{ } ,2000),
相对于传统的回调函数处理异步问题,Promise有以下几个好处:
- 解决了回调地狱的问题,以一种更线性的Promise链形式表达出来,更容易阅读和推断
- 回调函数难以处理错误:Promise链提供了一种让错误正确传播的途径
- 抽象表达:
-
Promise 是一门新的技术(ES6 规范)
-
Promise 是 JS 中进行异步编程的新解决方案
备注:旧方案是单纯使用回调函数
- 具体表达:
-
从语法上来说: Promise 是一个构造函数
-
从功能上来说: promise 对象用来封装一个异步操作并可以获取其成功/失败的结果值
二、Promise初体验
Promise
(承诺),给予调用者一个承诺,过一会返回数据给你,就可以创建一个promise对象- 当我们
new
一个promise
,此时我们需要传递一个回调函数,这个函数为立即执行的,称之为(executor) - 这个回调函数,我们需要传入两个参数回调函数
reslove
,reject
- 当执行了
reslove
函数,会回调promise对象的.then函数 - 当执行了
reject
函数,会回调promise对象的.catche函数
- 当执行了
抽奖样例(Promise实现):
<body>
<button onclick="draw()">点我抽奖</button>
<script>
function rand(m,n){
return Math.floor(Math.random()*n+m)
}
//按钮onclick事件的回调函数
function draw(){
//创建Promise对象,确定成功和失败的条件
//resolve方法和reject方法会将Promise对象状态设置为【成功】和【失败】
const p = new Promise((resolve,reject)=>{
var result=rand(1,100);
setTimeout(()=>{
if (result>=50) resolve(result);
else reject('badLuck')
},1000)
})
//调用then方法,指定成功和失败之后的回调
//then方法会根据Promise对象的状态来决定执行哪个函数
p.then((value)=>{
console.log('恭喜中奖!'+value);
},(reason)=>{
console.log('再接再厉!'+reason);
})
}
</script>
</body>
三、Promise 的状态改变
- pending 变为 resolved
- pending 变为 rejected
【说明】:
-
只有这 2 种, 且一个 promise 对象只能改变一次
-
无论变为成功还是失败, 都会有一个结果数据
-
成功的结果数据一般称为 value, 失败的结果数据一般称为 reason,可以通过resolve和reject函数传递给then中方法。
-
Promise的函数参数是同步执行的,then方法是异步的!
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
reject('失败')
resolve('成功')
}, 3000);
})
promise.then(res => console.log(res)).catch(err => console.log(err))
//失败
resolve不同值的区别
- 如果
resolve
传入一个普通的值或者对象,只能传递接受一个参数,那么这个值会作为then
回调的参数
const promise = new Promise((resolve, reject) => {
resolve({name: 'ice', age: 22})
})
promise.then(res => console.log(res))
// {name: 'ice', age: 22}
- 如果
resolve
中传入的是另外一个Promise
,那么这个新Promise
会决定原Promise
的状态
const promise = new Promise((resolve, reject) => {
resolve(new Promise((resolve, reject) => {
setTimeout(() => {
resolve('ice')
}, 3000);
}))
})
promise.then(res => console.log(res))
//3s后 ice
- 如果
resolve
中传入的是一个对象,并且这个对象有实现then
方法,那么会执行该then
方法,then
方法会传入resolve
,reject
函数。此时的promise
状态取决于你调用了resolve
,还是reject
函数。这种模式也称之为: thenable
const promise = new Promise((resolve, reject) => {
resolve({
then(res, rej) {
res('hi ice')
}
})
})
promise.then(res => console.log(res))
// hi ice
四、Promise的实例方法
1.then方法
then的参数
then
方法可以接受参数,一个参数为成功的回调,另一个参数为失败的回调
const promise = new Promise((resolve, reject) => {
resolve('request success')
// reject('request error')
})
promise.then(res => console.log(res), rej => console.log(rej))
//request success
then的多次调用
then的多次调用则会执行多次
const promise = new Promise((resolve, reject) => {
resolve('hi ice')
})
promise.then(res => console.log(res))
promise.then(res => console.log(res))
promise.then(res => console.log(res))
//hi ice
//hi ice
//hi ice
then的返回值
then
方法是有返回值的,它的返回值是promise
。
但是是promise
那它的状态如何决定呢?接下来让我们一探究竟。
-
返回一个普通值
-
则相当于主动调用
Promise.resolve
,并且把返回值作为实参传递到then
方法中 -
如果没有返回值,则相当于返回
undefined
-
-
返回一个Promise对象
那么取决于返回的这个Promise对象的状态
2.catch方法
catch的多次调用
同.then方法,也会执行多次
catch的返回值
catch方法也是有返回值的,返回的也是一个Promise对象,而且这个Promise对象的状态确定方法与then方法完全一致。
catch是用来处理异常的,那么catch与.then方法的第二个回调函数有什么区别呢?
catch与then第二个参数的区别
主要区别就是:如果在then的第一个函数里抛出了异常,后面的catch能捕获到,而then的第二个函数捕获不到。
3.finally方法
- ES9(2018)新实例方法
- finally(最后),无论promise状态是fulfilled还是rejected都会执行一次
finally
方法
五、Promise中的类方法/静态方法
1.Promise.reslove
Promise.resolve('ice')
//等价于
new Promise((resolve, reject) => resolve('ice'))
有的时候,你已经预知了状态的结果为fulfilled,则可以用这种简写方式
2.Promise.reject
类似地,可以得到一个状态为rejected的Promise对象
3.Promise.all
- all方法的参数传入为一个可迭代对象,返回一个promise,只有三个都为
resolve
状态的时候才会调用.then
方法。 - 只要有一个promise的状态为rejected,则会回调
.catch
方法
let p1 = new Promise((resolve, reject) => {
resolve('成功了')
})
let p2 = new Promise((resolve, reject) => {
resolve('success')
})
let p3 = Promise.reject('失败')
Promise.all([p1, p2]).then((result) => {
console.log(result) //['成功了', 'success']
}).catch((error) => {
console.log(error)
})
Promise.all([p1,p3,p2]).then((result) => {
console.log(result)
}).catch((error) => {
console.log(error) // 失败了,打出 '失败'
})
- 当遇到rejectd的时候,后续的promise结果我们是获取不到,并且会把reject的实参,传递给catch的err形参中
上面的
Promise.all
有一个缺陷,就是当遇到一个rejected的状态,那么对于后面是resolve
或者reject
的结果我们是拿不到的因此ES11 新增语法
Promise.allSettled
,无论状态是fulfilled/rejected都会把参数返回给我们
4.Promise.allSettled
const promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
reject('hi ice')
}, 1000);
})
const promise2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('hi panda')
}, 2000);
})
const promise3 = new Promise((resolve, reject) => {
setTimeout(() => {
reject('hi grizzly')
}, 3000);
})
Promise.allSettled([promise1, promise2, promise3]).then(res => console.log(res))
/* [
{ status: 'rejected', reason: 'hi ice' },
{ status: 'fulfilled', value: 'hi panda' },
{ status: 'rejected', reason: 'hi grizzly' }
] */
- 其中一个promise没有结果,则什么都结果都拿不到
5. Promise.race
- 优先获取第一个返回的结果,无论结果是fulfilled还是rejectd
const promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
reject('hi error')
}, 1000);
})
const promise2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('hi panda')
}, 2000);
})
Promise.race([promise1, promise2])
.then(res => console.log(res))
.catch(e => console.log(e))
//hi error
6.Promise.any
- 与race类似,但是只获取第一个状态为fulfilled,如果全部为rejected则报错
AggregateError
六、async 与 await
异步函数(async function)中可以使用await
关键字,普通函数不行
-
通常await关键字后面都是跟一个Promise
- 可以是普通值
- 可以是thenable
- 可以是Promise主动调用
resolve或者reject
-
这个promise状态变为fulfilled才会执行
await
后续的代码,所以await
后面的代码,相当于包括在.then
方法的回调中如果状态变为rejected,你则需要在函数内部
try catch
,或者进行链式调用进行.catch
操作