promise
是异步编程及回调地狱的一种解决方案,
有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。
只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。
所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。
Promise也有一些缺点。首先,无法取消Promise,一旦新建它就会立即执行,无法中途取消。其次,如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。第三,当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。
- 基本案例
// 这里我就使用setTimeout 模拟ajax
let name = new Promise((resolve,reject)=>{
setTimeout(function(){
// let name = '张三' // 请求成功拿到数据
let name = null // 请求失败
if (name){
resolve(name); // 传递成功结果,改变为fulfilled状态
} else {
reject('获取失败!') // 传递成功结果,改变为rejected状态
}
},1000)
})
console.log(name)
name.then(res=>{ // then(callback(res,err))
console.log(res)
})
.catch(err=>{ // 失败回调函数
console.log(err)
})
.finally(()=>{
console.log('不管成功或者失败都会执行!')
})
- 案例二(解决回调地狱)
- 需求:三级联动,查找下一级需要上一级的id,通过接口实现
// 不使用promise
function getProvince(){
let cityStr = ''
setTimeout(()=>{ // 请求拿到省
cityStr+='山西省'
setTimeout(()=>{ // 请求拿到市
cityStr+='太原市'
setTimeout(()=>{ // 请求拿到区
cityStr+='小店区'
console.log(cityStr)
// 像这种一层一层嵌套的叫做回调地狱,如果嵌套层数越多,阅读和维护就变的异常困难
},500)
},500)
},500)
}
getProvince()
// 使用promise
let p1 = new Promise((resolve,reject)=>{
setTimeout(()=>{
// resolve('山西省')
reject('省错误')
},1000)
})
let p2 = new Promise((resolve,reject)=>{
setTimeout(()=>{
// resolve('太原市')
reject('市,错误')
},2000)
})
let p3 = new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve('小店区')
},3000)
})
p1.then(res=>{
console.log('省:'+res)
return p2
}).then(res=>{
console.log('市:'+res)
return p3
}).then(res=>{
console.log('区:'+res)
}).catch(err=>{// 中途如有错误,那么就会抛出当前错误,并停止执行
console.log(err)
}) // 我们发现,看起来解决了无限嵌套的问题,但是代码量带多了,那么我们换一种思路实现
- 改进后的promise
// 使用promise,改进后
function getPromise(params){ // 封装请求
return new Promise((resolve,reject)=>{
setTimeout(()=>{ // 表示请求
resolve(params)
// if(params === '市的接口'){
// reject('市级,获取失败!')
// }
},1000)
})
}
getPromise('省的接口').then(res=>{
console.log(res)
return getPromise('市的接口')
}).then(res=>{
console.log(res)
return getPromise('区的接口')
}).then(res=>{
console.log(res)
}) .catch(err=>{
console.log('错误:'+err)
}) // 是不是看起来简介了很多~~
Promise.all()
/**
* Promise.all()方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。
* 注意,如果作为参数的 Promise 实例,自己定义了catch方法,那么它一旦被rejected,并不会触发Promise.all()的catch方法。
* */
Promise.all([p1,p2,p3])
.then(res=>{
// all等待所有的结果成功返回后,才会执行,
// 中途有错误,那么就会报错(当前请求的错误),没有返回值, 也就是说不会执行
console.log(res)
}).catch(err=>{
console.log(err)
})
Promise.allSettled()
/**
* Promise.allSettled()
* 没有catch失败回调函数
* 一旦结束,状态总是fulfilled,返回数组对象如:
* [
{
"status": "rejected",
"reason": "省错误"
},
{
"status": "rejected",
"reason": "市,错误"
},
{
"status": "fulfilled",
"value": "小店区"
}
]
* 我们可以根据 status 状态来 来输出原因!
*/
Promise.allSettled([p1,p2,p3])
.then(res=>{
console.log(res)
})
Promise.race()
/**
* Promise.race()
* 多个 Promise 实例,包装成一个新的 Promise 实例
* race(顾名思义是竞赛的意思)
* 只要p1、p2、p3之中有一个实例率先返回,那个率先改变的 Promise 实例的返回值,就传递给p的回调函数
* 注意:如果率先放回的状态为失败,那么就抛出错误,并停止执行
*/
Promise.race([p1,p2,p3])
.then(res=>{
console.log(res) // 只显示第一个返回的实例值
}).catch(err=>{
console.log(err)
});
Promise.any()
/**
* Promise.any()
* 跟Promise.race() 很相似,唯一区别是,就是不会因为某个 Promise 变成rejected状态而结束。
* 注意:如果率先放回的状态为失败,那么会继续执行下一个,直到某个成功后,停止执行
*/
Promise.any([p1,p2,p3])
.then(res=>{
console.log(res) // 只显示第一个返回的实例值
}).catch(err=>{
console.log(err)
});