概述:Promise是处理异步问题的一种方式,之前都是用回调函数,如setTimeout( ( )=>{ } ,2000),
相对于传统的回调函数处理异步问题,Promise有以下几个好处:
Promise 是一门新的技术(ES6 规范)
Promise 是 JS 中进行异步编程的新解决方案
备注:旧方案是单纯使用回调函数
从语法上来说: 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>
【说明】:
只有这 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
传入一个普通的值或者对象,只能传递接受一个参数,那么这个值会作为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
函数。这种模式也称之为: thenableconst promise = new Promise((resolve, reject) => {
resolve({
then(res, rej) {
res('hi ice')
}
})
})
promise.then(res => console.log(res))
// hi ice
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的多次调用则会执行多次
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
方法是有返回值的,它的返回值是promise
。
但是是promise
那它的状态如何决定呢?接下来让我们一探究竟。
返回一个普通值
则相当于主动调用Promise.resolve
,并且把返回值作为实参传递到then
方法中
如果没有返回值,则相当于返回undefined
返回一个Promise对象
那么取决于返回的这个Promise对象的状态
同.then方法,也会执行多次
catch方法也是有返回值的,返回的也是一个Promise对象,而且这个Promise对象的状态确定方法与then方法完全一致。
catch是用来处理异常的,那么catch与.then方法的第二个回调函数有什么区别呢?
主要区别就是:如果在then的第一个函数里抛出了异常,后面的catch能捕获到,而then的第二个函数捕获不到。
finally
方法Promise.resolve('ice')
//等价于
new Promise((resolve, reject) => resolve('ice'))
有的时候,你已经预知了状态的结果为fulfilled,则可以用这种简写方式
类似地,可以得到一个状态为rejected的Promise对象
resolve
状态的时候才会调用.then
方法。.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) // 失败了,打出 '失败'
})
上面的
Promise.all
有一个缺陷,就是当遇到一个rejected的状态,那么对于后面是resolve
或者reject
的结果我们是拿不到的因此ES11 新增语法
Promise.allSettled
,无论状态是fulfilled/rejected都会把参数返回给我们
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' }
] */
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
AggregateError
异步函数(async function)中可以使用await
关键字,普通函数不行
通常await关键字后面都是跟一个Promise
resolve或者reject
这个promise状态变为fulfilled才会执行await
后续的代码,所以await
后面的代码,相当于包括在.then
方法的回调中
如果状态变为rejected,你则需要在函数内部try catch
,或者进行链式调用进行.catch
操作